/ concept-collection / mesh-studio
Sign in
concept-collection / mesh-studio
mesh-studio / src / occ / primitives.ts
107 lines · 4.4 KBBlameHistoryRaw
1/**
2 * Built-in CAD primitives, each returning a `TopoDS_Shape`. These exercise the
3 * range of OpenCASCADE face types: analytic (sphere/torus/cylinder/cone) and,
4 * once fillets or fusions are involved, genuine free-form NURBS faces.
5 *
6 * Overload suffixes (`_1`, `_2`, …) follow OCCT header declaration order and
7 * mirror the usage in the opencascade.js examples.
8 */
9import type { OpenCascade, Shape } from './types'
11export function makeSphere(oc: OpenCascade, radius = 1): Shape {
12 return new oc.BRepPrimAPI_MakeSphere_1(radius).Shape()
15export function makeBox(oc: OpenCascade, dx = 1.5, dy = 1, dz = 1): Shape {
16 return new oc.BRepPrimAPI_MakeBox_2(dx, dy, dz).Shape()
19export function makeCylinder(oc: OpenCascade, radius = 0.7, height = 1.6): Shape {
20 return new oc.BRepPrimAPI_MakeCylinder_1(radius, height).Shape()
23export function makeCone(oc: OpenCascade, r1 = 0.9, r2 = 0.25, height = 1.5): Shape {
24 return new oc.BRepPrimAPI_MakeCone_1(r1, r2, height).Shape()
27export function makeTorus(oc: OpenCascade, major = 1, minor = 0.35): Shape {
28 return new oc.BRepPrimAPI_MakeTorus_1(major, minor).Shape()
31/** A box with all edges rounded — introduces free-form NURBS fillet faces. */
32export function makeFilletBox(oc: OpenCascade, dx = 1.4, dy = 1, dz = 1, radius = 0.22): Shape {
33 const box = new oc.BRepPrimAPI_MakeBox_2(dx, dy, dz).Shape()
34 const mkFillet = new oc.BRepFilletAPI_MakeFillet(box, oc.ChFi3d_FilletShape.ChFi3d_Rational)
35 const exp = new oc.TopExp_Explorer_2(
36 box,
37 oc.TopAbs_ShapeEnum.TopAbs_EDGE,
38 oc.TopAbs_ShapeEnum.TopAbs_SHAPE,
39 )
40 while (exp.More()) {
41 mkFillet.Add_2(radius, oc.TopoDS.Edge_1(exp.Current()))
42 exp.Next()
43 }
44 exp.delete()
45 return mkFillet.Shape()
48/**
49 * The classic OpenCASCADE "bottle" tutorial shape (filleted body + threaded
50 * neck), adapted from opencascade.js-examples. A rich mix of planar, swept and
51 * lofted faces — a good stress test for tessellation and NURBS extraction.
52 */
53export function makeBottle(oc: OpenCascade, myWidth = 1.0, myHeight = 1.4, myThickness = 0.6): Shape {
54 const aPnt1 = new oc.gp_Pnt_3(-myWidth / 2, 0, 0)
55 const aPnt2 = new oc.gp_Pnt_3(-myWidth / 2, -myThickness / 4, 0)
56 const aPnt3 = new oc.gp_Pnt_3(0, -myThickness / 2, 0)
57 const aPnt4 = new oc.gp_Pnt_3(myWidth / 2, -myThickness / 4, 0)
58 const aPnt5 = new oc.gp_Pnt_3(myWidth / 2, 0, 0)
60 const anArcOfCircle = new oc.GC_MakeArcOfCircle_4(aPnt2, aPnt3, aPnt4)
61 const aSegment1 = new oc.GC_MakeSegment_1(aPnt1, aPnt2)
62 const aSegment2 = new oc.GC_MakeSegment_1(aPnt4, aPnt5)
64 const anEdge1 = new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(aSegment1.Value().get()))
65 const anEdge2 = new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(anArcOfCircle.Value().get()))
66 const anEdge3 = new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(aSegment2.Value().get()))
67 const aWire = new oc.BRepBuilderAPI_MakeWire_4(anEdge1.Edge(), anEdge2.Edge(), anEdge3.Edge())
69 const xAxis = oc.gp.OX()
70 const aTrsf = new oc.gp_Trsf_1()
71 aTrsf.SetMirror_2(xAxis)
72 const aBRepTrsf = new oc.BRepBuilderAPI_Transform_2(aWire.Wire(), aTrsf, false)
73 const aMirroredShape = aBRepTrsf.Shape()
75 const mkWire = new oc.BRepBuilderAPI_MakeWire_1()
76 mkWire.Add_2(aWire.Wire())
77 mkWire.Add_2(oc.TopoDS.Wire_1(aMirroredShape))
78 const myWireProfile = mkWire.Wire()
80 const myFaceProfile = new oc.BRepBuilderAPI_MakeFace_15(myWireProfile, false)
81 const aPrismVec = new oc.gp_Vec_4(0, 0, myHeight)
82 let myBody: Shape = new oc.BRepPrimAPI_MakePrism_1(myFaceProfile.Face(), aPrismVec, false, true)
84 const mkFillet = new oc.BRepFilletAPI_MakeFillet(myBody.Shape(), oc.ChFi3d_FilletShape.ChFi3d_Rational)
85 const anEdgeExplorer = new oc.TopExp_Explorer_2(
86 myBody.Shape(),
87 oc.TopAbs_ShapeEnum.TopAbs_EDGE,
88 oc.TopAbs_ShapeEnum.TopAbs_SHAPE,
89 )
90 while (anEdgeExplorer.More()) {
91 const anEdge = oc.TopoDS.Edge_1(anEdgeExplorer.Current())
92 mkFillet.Add_2(myThickness / 12, anEdge)
93 anEdgeExplorer.Next()
94 }
95 myBody = mkFillet.Shape()
97 const neckLocation = new oc.gp_Pnt_3(0, 0, myHeight)
98 const neckAxis = oc.gp.DZ()
99 const neckAx2 = new oc.gp_Ax2_3(neckLocation, neckAxis)
100 const myNeckRadius = myThickness / 4
101 const myNeckHeight = myHeight / 10
102 const MKCylinder = new oc.BRepPrimAPI_MakeCylinder_3(neckAx2, myNeckRadius, myNeckHeight)
103 const myNeck = MKCylinder.Shape()
104 myBody = new oc.BRepAlgoAPI_Fuse_3(myBody, myNeck, new oc.Message_ProgressRange_1())
106 return myBody.Shape()
moveopenescclose