RepliCAD

Форк
0
/
shapeHelpers.ts 
499 строк · 11.8 Кб
1
import {
2
  AnyShape,
3
  Edge,
4
  Face,
5
  Wire,
6
  Solid,
7
  Vertex,
8
  cast,
9
  downcast,
10
  Shape3D,
11
  isShape3D,
12
  Shell,
13
} from "./shapes";
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";
19

20
export const makeLine = (v1: Point, v2: Point): Edge => {
21
  const oc = getOC();
22
  return new Edge(
23
    new oc.BRepBuilderAPI_MakeEdge_3(asPnt(v1), asPnt(v2)).Edge()
24
  );
25
};
26

27
export const makeCircle = (
28
  radius: number,
29
  center: Point = [0, 0, 0],
30
  normal: Point = [0, 0, 1]
31
): Edge => {
32
  const oc = getOC();
33
  const [r, gc] = localGC();
34

35
  const ax = r(makeAx2(center, normal));
36

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());
40
  gc();
41

42
  return shape;
43
};
44

45
export const makeEllipse = (
46
  majorRadius: number,
47
  minorRadius: number,
48
  center: Point = [0, 0, 0],
49
  normal: Point = [0, 0, 1],
50
  xDir?: Point
51
): Edge => {
52
  const oc = getOC();
53
  const [r, gc] = localGC();
54

55
  const ax = r(makeAx2(center, normal, xDir));
56

57
  if (minorRadius > majorRadius) {
58
    throw new Error("The minor radius must be smaller than the major one");
59
  }
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());
63
  gc();
64

65
  return shape;
66
};
67

68
export const makeHelix = (
69
  pitch: number,
70
  height: number,
71
  radius: number,
72
  center: Point = [0, 0, 0],
73
  dir: Point = [0, 0, 1],
74
  lefthand = false
75
): Edge => {
76
  const oc = getOC();
77
  const [r, gc] = localGC();
78
  let myDir = 2 * Math.PI;
79
  if (lefthand) {
80
    myDir = -2 * Math.PI;
81
  }
82

83
  const geomLine = r(
84
    new oc.Geom2d_Line_3(
85
      r(new oc.gp_Pnt2d_3(0.0, 0.0)),
86
      r(new oc.gp_Dir2d_4(myDir, pitch))
87
    )
88
  );
89

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)
95
  );
96
  const geomSeg = r(new oc.GCE2d_MakeSegment_1(uStart, uStop));
97

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)),
101
    radius
102
  );
103

104
  const e = r(
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))
108
    )
109
  ).Edge();
110

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);
114

115
  gc();
116

117
  return new Edge(w);
118
};
119

120
export const makeThreePointArc = (v1: Point, v2: Point, v3: Point): Edge => {
121
  const oc = getOC();
122
  const circleGeom = new oc.GC_MakeArcOfCircle_4(
123
    asPnt(v1),
124
    asPnt(v2),
125
    asPnt(v3)
126
  ).Value();
127

128
  const curve = new oc.Handle_Geom_Curve_2(circleGeom.get());
129
  return new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
130
};
131

132
export const makeEllipseArc = (
133
  majorRadius: number,
134
  minorRadius: number,
135
  startAngle: number,
136
  endAngle: number,
137
  center: Point = [0, 0, 0],
138
  normal: Point = [0, 0, 1],
139
  xDir?: Point
140
): Edge => {
141
  const oc = getOC();
142
  const [r, gc] = localGC();
143

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");
147
  }
148

149
  const ellipseGp = r(new oc.gp_Elips_2(ax, majorRadius, minorRadius));
150
  const edgeMaker = r(
151
    new oc.BRepBuilderAPI_MakeEdge_13(ellipseGp, startAngle, endAngle)
152
  );
153
  const shape = new Edge(edgeMaker.Edge());
154
  gc();
155

156
  return shape;
157
};
158

159
export interface BSplineApproximationConfig {
160
  tolerance?: number;
161
  degMax?: number;
162
  degMin?: number;
163
  smoothing?: null | [number, number, number];
164
}
165

166
export const makeBSplineApproximation = function makeBSplineApproximation(
167
  points: Point[],
168
  {
169
    tolerance = 1e-3,
170
    smoothing = null,
171
    degMax = 6,
172
    degMin = 1,
173
  }: BSplineApproximationConfig = {}
174
): Edge {
175
  const oc = getOC();
176
  const [r, gc] = localGC();
177

178
  const pnts = r(new oc.TColgp_Array1OfPnt_2(1, points.length));
179

180
  points.forEach((point, index) => {
181
    pnts.SetValue(index + 1, r(asPnt(point)));
182
  });
183

184
  let splineBuilder: GeomAPI_PointsToBSpline;
185

186
  if (smoothing) {
187
    splineBuilder = r(
188
      new oc.GeomAPI_PointsToBSpline_5(
189
        pnts,
190
        smoothing[0],
191
        smoothing[1],
192
        smoothing[2],
193
        degMax,
194
        oc.GeomAbs_Shape.GeomAbs_C2 as any,
195
        tolerance
196
      )
197
    );
198
  } else {
199
    splineBuilder = r(
200
      new oc.GeomAPI_PointsToBSpline_2(
201
        pnts,
202
        degMin,
203
        degMax,
204
        oc.GeomAbs_Shape.GeomAbs_C2 as any,
205
        tolerance
206
      )
207
    );
208
  }
209

210
  if (!splineBuilder.IsDone()) {
211
    gc();
212
    throw new Error("B-spline approximation failed");
213
  }
214

215
  const splineGeom = r(splineBuilder.Curve());
216

217
  const curve = r(new oc.Handle_Geom_Curve_2(splineGeom.get()));
218
  const edge = new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
219
  gc();
220
  return edge;
221
};
222

223
export const makeBezierCurve = (points: Point[]): Edge => {
224
  const oc = getOC();
225
  const arrayOfPoints = new oc.TColgp_Array1OfPnt_2(1, points.length);
226
  points.forEach((p, i) => {
227
    arrayOfPoints.SetValue(i + 1, asPnt(p));
228
  });
229
  const bezCurve = new oc.Geom_BezierCurve_1(arrayOfPoints);
230

231
  const curve = new oc.Handle_Geom_Curve_2(bezCurve);
232
  return new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
233
};
234

235
export const makeTangentArc = (
236
  startPoint: Point,
237
  startTgt: Point,
238
  endPoint: Point
239
): Edge => {
240
  const oc = getOC();
241
  const [r, gc] = localGC();
242
  const circleGeom = r(
243
    new oc.GC_MakeArcOfCircle_5(
244
      r(asPnt(startPoint)),
245
      new Vector(startTgt).wrapped,
246
      r(asPnt(endPoint))
247
    ).Value()
248
  );
249

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());
252
  gc();
253
  return edge;
254
};
255

256
/*
257
const assembleEdgesAsWire = (listOfEdges: (Edge)[]): Wire => {
258
    const edges
259

260

261
}
262
*/
263

264
export const assembleWire = (listOfEdges: (Edge | Wire)[]): Wire => {
265
  const oc = getOC();
266
  const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
267
  listOfEdges.forEach((e) => {
268
    if (e instanceof Edge) {
269
      wireBuilder.Add_1(e.wrapped);
270
    }
271
    if (e instanceof Wire) {
272
      wireBuilder.Add_2(e.wrapped);
273
    }
274
  });
275

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"],
282
      [
283
        oc.BRepBuilderAPI_WireError.BRepBuilderAPI_NonManifoldWire,
284
        "non manifold wire",
285
      ],
286
      [
287
        oc.BRepBuilderAPI_WireError.BRepBuilderAPI_DisconnectedWire,
288
        "disconnected wire",
289
      ],
290
    ]);
291
    throw new Error(
292
      `Failed to build the wire, ${errorNames.get(res) || "unknown error"}`
293
    );
294
  }
295

296
  const wire = new Wire(wireBuilder.Wire());
297
  wireBuilder.delete();
298
  progress.delete();
299
  return wire;
300
};
301

302
export const makeFace = (wire: Wire, holes?: Wire[]): Face => {
303
  const oc = getOC();
304
  const faceBuilder = new oc.BRepBuilderAPI_MakeFace_15(wire.wrapped, false);
305
  holes?.forEach((hole) => {
306
    faceBuilder.Add(hole.wrapped);
307
  });
308
  if (!faceBuilder.IsDone()) {
309
    faceBuilder.delete();
310
    throw new Error("Failed to build the face. Your wire might be non planar.");
311
  }
312
  const face = faceBuilder.Face();
313
  faceBuilder.delete();
314

315
  return new Face(face);
316
};
317

318
export const makeNewFaceWithinFace = (originFace: Face, wire: Wire) => {
319
  const oc = getOC();
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)
324
  );
325
  const face = faceBuilder.Face();
326
  gc();
327

328
  return new Face(face);
329
};
330

331
export const makeNonPlanarFace = (wire: Wire): Face => {
332
  const oc = getOC();
333
  const [r, gc] = localGC();
334

335
  const faceBuilder = r(
336
    new oc.BRepOffsetAPI_MakeFilling(
337
      3,
338
      15,
339
      2,
340
      false,
341
      1e-5,
342
      1e-4,
343
      1e-2,
344
      0.1,
345
      8,
346
      9
347
    )
348
  );
349
  wire.edges.forEach((edge) => {
350
    faceBuilder.Add_1(
351
      r(edge).wrapped,
352
      oc.GeomAbs_Shape.GeomAbs_C0 as any,
353
      true
354
    );
355
  });
356

357
  const progress = r(new oc.Message_ProgressRange_1());
358
  faceBuilder.Build(progress);
359
  const newFace = cast(faceBuilder.Shape());
360

361
  gc();
362

363
  if (!(newFace instanceof Face)) {
364
    throw new Error("Failed to create a face");
365
  }
366
  return newFace;
367
};
368

369
export const makeCylinder = (
370
  radius: number,
371
  height: number,
372
  location: Point = [0, 0, 0],
373
  direction: Point = [0, 0, 1]
374
): Solid => {
375
  const oc = getOC();
376
  const axis = makeAx2(location, direction);
377

378
  const cylinder = new oc.BRepPrimAPI_MakeCylinder_3(axis, radius, height);
379
  const solid = new Solid(cylinder.Shape());
380
  axis.delete();
381
  cylinder.delete();
382
  return solid;
383
};
384

385
export const makeSphere = (radius: number): Solid => {
386
  const oc = getOC();
387

388
  const sphereMaker = new oc.BRepPrimAPI_MakeSphere_1(radius);
389
  const sphere = new Solid(sphereMaker.Shape());
390
  sphereMaker.delete();
391
  return sphere;
392
};
393

394
export const makeVertex = (point: Point): Vertex => {
395
  const oc = getOC();
396
  const pnt = asPnt(point);
397

398
  const vertexMaker = new oc.BRepBuilderAPI_MakeVertex(pnt);
399
  const vertex = vertexMaker.Vertex();
400
  vertexMaker.delete();
401

402
  return new Vertex(vertex);
403
};
404

405
export const makeOffset = (
406
  face: Face,
407
  offset: number,
408
  tolerance = 1e-6
409
): Shape3D => {
410
  const oc = getOC();
411
  const progress = new oc.Message_ProgressRange_1();
412
  const offsetBuilder = new oc.BRepOffsetAPI_MakeOffsetShape();
413
  offsetBuilder.PerformByJoin(
414
    face.wrapped,
415
    offset,
416
    tolerance,
417
    oc.BRepOffset_Mode.BRepOffset_Skin as any,
418
    false,
419
    false,
420
    oc.GeomAbs_JoinType.GeomAbs_Arc as any,
421
    false,
422
    progress
423
  );
424

425
  const newShape = cast(downcast(offsetBuilder.Shape()));
426
  offsetBuilder.delete();
427
  progress.delete();
428

429
  if (!isShape3D(newShape)) throw new Error("Could not offset to a 3d shape");
430
  return newShape;
431
};
432

433
export const compoundShapes = (shapeArray: AnyShape[]): AnyShape => {
434
  const oc = getOC();
435
  const builder = new oc.TopoDS_Builder();
436
  const compound = new oc.TopoDS_Compound();
437
  builder.MakeCompound(compound);
438

439
  shapeArray.forEach((s) => {
440
    builder.Add(compound, s.wrapped);
441
    s.delete();
442
  });
443

444
  const newShape = cast(compound);
445
  return newShape;
446
};
447

448
export const makeCompound = compoundShapes;
449

450
export function makeSolid(facesOrShells: Array<Face | Shell>): Solid {
451
  const oc = getOC();
452
  const [r, gc] = localGC();
453
  const shellBuilder = r(
454
    new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false)
455
  );
456

457
  facesOrShells.forEach(({ wrapped }) => {
458
    shellBuilder.Add(wrapped);
459
  });
460

461
  shellBuilder.Perform(r(new oc.Message_ProgressRange_1()));
462

463
  const shell = r(downcast(shellBuilder.SewedShape()));
464
  const solid = cast(r(new oc.ShapeFix_Solid_1()).SolidFromShell(shell));
465

466
  gc();
467
  if (!(solid instanceof Solid))
468
    throw new Error("Could not make a solid of faces and shells");
469

470
  return solid;
471
}
472

473
export const addHolesInFace = (face: Face, holes: Wire[]): Face => {
474
  const oc = getOC();
475
  const [r, gc] = localGC();
476

477
  const faceMaker = r(new oc.BRepBuilderAPI_MakeFace_2(face.wrapped));
478
  holes.forEach((wire) => {
479
    faceMaker.Add(wire.wrapped);
480
  });
481

482
  const builtFace = r(faceMaker.Face());
483

484
  const fixer = r(new oc.ShapeFix_Face_2(builtFace));
485
  fixer.FixOrientation_1();
486
  const newFace = fixer.Face();
487

488
  gc();
489
  return new Face(newFace);
490
};
491

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)
497
  );
498
  return makeFace(assembleWire(edges));
499
};
500

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.