Shells
Shells are fundamental geometric constructs in OCCT that represent connected collections of faces. Think of a shell as the "skin" of a 3D object - it defines the boundary between the interior and exterior of a shape but doesn't necessarily enclose a volume. Shells are particularly useful for creating complex surfaces, modeling thin-walled objects, or as intermediate steps toward creating solid geometries.
What Are Shells?
A shell is essentially a collection of faces that are sewn together along their common edges. Unlike individual faces that exist independently, shells maintain topological connections between faces, creating a unified surface structure. This connectivity is crucial for many geometric operations and enables OCCT to understand the relationship between adjacent surfaces.
Shells can be either open (like a curved sheet of paper) or closed (like a complete sphere surface). Closed shells that properly enclose a volume can be converted into solid geometries, making them valuable intermediate representations in 3D modeling workflows.
The Sewing Process
The process of creating shells involves "sewing" faces together by identifying and connecting their common edges. OCCT's sewing algorithm automatically detects edges that are geometrically coincident within a specified tolerance and merges them into shared boundaries. This process ensures topological consistency and creates the connected face structure that defines a shell.
When creating shells, the first face in the collection often dictates how other face normals and orientations behave during the sewing process. OCCT uses the orientation of the first face as a reference to determine the consistent orientation for the entire shell. This is particularly important when creating closed shells that will be converted to solids, as inconsistent face orientations can prevent successful solid creation.
Simple Shell Example: Two Square Faces
This first example demonstrates the fundamental concept of shell creation by sewing two square faces together. We create two identical square faces, position one of them to share an edge with the first, and then sew them together to form a simple shell.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"9cc2b5b030cd6544": {
"id": "9cc2b5b030cd6544",
"name": "bitbybit.occt.shapes.face.createSquareFace",
"customName": "square face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"size": 10,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"size": {
"connections": [
{
"node": "6ab6165c86c75d5b",
"output": "result",
"data": {}
}
]
}
},
"position": [
388.640625,
318.28125
]
},
"37ac5c3a76a47a41": {
"id": "37ac5c3a76a47a41",
"name": "bitbybit.occt.shapes.face.createSquareFace",
"customName": "square face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"size": 10,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"size": {
"connections": [
{
"node": "6ab6165c86c75d5b",
"output": "result",
"data": {}
}
]
}
},
"position": [
384.3828125,
682.85546875
]
},
"a26904db90e232fa": {
"id": "a26904db90e232fa",
"name": "bitbybit.occt.transforms.rotate",
"customName": "rotate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"axis": [
0,
0,
1
],
"angle": 90
},
"inputs": {
"shape": {
"connections": [
{
"node": "37ac5c3a76a47a41",
"output": "result",
"data": {}
}
]
}
},
"position": [
761.9724216130267,
679.9104125282475
]
},
"e20d8e52af5decc2": {
"id": "e20d8e52af5decc2",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
0,
0,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "a26904db90e232fa",
"output": "result",
"data": {}
}
]
},
"translation": {
"connections": [
{
"node": "b79751538f6d9332",
"output": "result",
"data": {}
}
]
}
},
"position": [
1174.9413459447806,
677.2007871438307
]
},
"b79751538f6d9332": {
"id": "b79751538f6d9332",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"x": {
"connections": [
{
"node": "19813c3c61a9eb1a",
"output": "result",
"data": {}
}
]
},
"y": {
"connections": [
{
"node": "19813c3c61a9eb1a",
"output": "result",
"data": {}
}
]
}
},
"position": [
767.8304944712777,
1091.384077461372
]
},
"6ab6165c86c75d5b": {
"id": "6ab6165c86c75d5b",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"number": 5
},
"inputs": {},
"position": [
-265.8387776639955,
723.1249190057332
]
},
"19813c3c61a9eb1a": {
"id": "19813c3c61a9eb1a",
"name": "bitbybit.math.divide",
"customName": "divide",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2
},
"inputs": {
"first": {
"connections": [
{
"node": "6ab6165c86c75d5b",
"output": "result",
"data": {}
}
]
}
},
"position": [
387.43372760259007,
1096.9354814858784
]
},
"a4b016dfef41eacd": {
"id": "a4b016dfef41eacd",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "9cc2b5b030cd6544",
"output": "result",
"data": {}
},
{
"node": "e20d8e52af5decc2",
"output": "result",
"data": {}
}
]
}
},
"position": [
1690.8443384003301,
360.2420878436985
]
},
"8a4197bae2968d16": {
"id": "8a4197bae2968d16",
"name": "bitbybit.occt.shapes.shell.sewFaces",
"customName": "sew faces",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7
},
"inputs": {
"shapes": {
"connections": [
{
"node": "a4b016dfef41eacd",
"output": "list",
"data": {}
}
]
}
},
"position": [
2064.5100977893935,
319.05861267945994
]
},
"d8210eae815ee860": {
"id": "d8210eae815ee860",
"name": "bitbybit.occt.shapes.shape.getShapeType",
"customName": "get shape type",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "8a4197bae2968d16",
"output": "result",
"data": {}
}
]
}
},
"position": [
2441.2409711581986,
317.30920053451604
]
},
"1a6e2944a7fbf825": {
"id": "1a6e2944a7fbf825",
"name": "bitbybit.previewData",
"customName": "preview data",
"data": {
"previewJSONControl": "[\n \"shell\"\n]"
},
"inputs": {
"data": {
"connections": [
{
"node": "d8210eae815ee860",
"output": "result",
"data": {}
}
]
}
},
"position": [
2815.9187871600393,
355.1528888765889
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="2j#UKo}(~;^`c8a2]Lzc">size</variable><variable id="ItXu:Dn?)s,v)b.oMN=?">face1</variable><variable id="#[4{#RSNUOD}~]X]~o$<">face2</variable><variable id="h*,JaG2g2kl+h7?hCa-1">rotatedFace2</variable><variable id="J!fA.:+w-ywlhH2i*Aq4">translatedFace2</variable><variable id="a%e_#NZ$KjnM<K(j}`:)">faces</variable><variable id="^/xo7LZ:%?M._xp*+:5:">shell</variable></variables><block type="variables_set" id="d8m/|*I~0)uKZTvE}L{4" x="-267" y="-366"><field name="VAR" id="2j#UKo}(~;^`c8a2]Lzc">size</field><value name="VALUE"><block type="math_number" id="OTp/h]kN}pQ@|]/JzWxj"><field name="NUM">5</field></block></value><next><block type="variables_set" id="AW9X]*~,C>!y.c6U31NM"><field name="VAR" id="ItXu:Dn?)s,v)b.oMN=?">face1</field><value name="VALUE"><block type="bitbybit.occt.shapes.face.createSquareFace" id="M2*W.{VG{WKWGm5+x)y]"><value name="Size"><block type="variables_get" id="x(v@]5[rG0pVm*bG@!~d"><field name="VAR" id="2j#UKo}(~;^`c8a2]Lzc">size</field></block></value><value name="Center"><block type="lists_create_with" id="[I^6+Yz]Ss$%`^/J6BvJ"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="hXjT0A*X(VRBCfF$gCHh"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="8_K6gP6NB!uWJU7l|6}v"><field name="NUM">0</field></block></value><value name="ADD2"><block type="math_number" id="%X`K>)K[DYSMdE#?n!gt"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="lists_create_with" id="Y>i;Rj+XA$*E?*>h?A+S"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="r8<)cV!|S2j?Y$ZP1!*3"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="PItF@_Z>]x{SWe:s[VNK"><field name="NUM">1</field></block></value><value name="ADD2"><block type="math_number" id="Kh$1*t:LBD%)dSk)9;R!"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="UQzD?M{(FBN^U%*3Dqyt"><field name="VAR" id="#[4{#RSNUOD}~]X]~o$<">face2</field><value name="VALUE"><block type="bitbybit.occt.shapes.face.createSquareFace" id="gvC,M.WE{~GEE5Ap_>o4"><value name="Size"><block type="variables_get" id="fhi>mOyMnGNxK_g]!:LN"><field name="VAR" id="2j#UKo}(~;^`c8a2]Lzc">size</field></block></value><value name="Center"><block type="lists_create_with" id="v[?uu_fqONQC_<3?EEf("><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="5v).=|K@)g!ux_N>k,<D"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="?Sw{#Q|QJ~r<5/]^GN;&"><field name="NUM">0</field></block></value><value name="ADD2"><block type="math_number" id="_^>2Xjh^,tON[*W7cQ%I"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="lists_create_with" id="w~2ZR-l5~qvM8f3dP+7O"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="@T8OLH5[cY=hNKi6DzIr"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="JRx#U>L@n_,eB;:r,)vF"><field name="NUM">1</field></block></value><value name="ADD2"><block type="math_number" id="O8(,lGOo!H(6SsL_CJ?U"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="6oW<IG4;J!]aT`k;9{tz"><field name="VAR" id="h*,JaG2g2kl+h7?hCa-1">rotatedFace2</field><value name="VALUE"><block type="bitbybit.occt.transforms.rotate" id="7d%fv!=)q{Q]v,.FG#]H"><value name="Shape"><block type="variables_get" id="GlG!8SZ+lJB7x%X?1[*w"><field name="VAR" id="#[4{#RSNUOD}~]X]~o$<">face2</field></block></value><value name="Axis"><block type="lists_create_with" id="hPu[r[#*x>%}L?K7s9)U"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="1nq$:aK>wHF}vI*?S8(4"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="!$X?=^tKb~lCA]bT?1C:"><field name="NUM">0</field></block></value><value name="ADD2"><block type="math_number" id="}Eb!5hSG}sGBuI:e!K(_"><field name="NUM">1</field></block></value></block></value><value name="Angle"><block type="math_number" id="Ks6(4=x%.YQ%9nZA1Xze"><field name="NUM">90</field></block></value></block></value><next><block type="variables_set" id="PFIqgZ,hZo%UQv!ddhJ%"><field name="VAR" id="J!fA.:+w-ywlhH2i*Aq4">translatedFace2</field><value name="VALUE"><block type="bitbybit.occt.transforms.translate" id="Gg8v]+u3D|t?b$|6{.G2"><value name="Shape"><block type="variables_get" id=",G&Cq3LPFq1>+MKvU]3>"><field name="VAR" id="h*,JaG2g2kl+h7?hCa-1">rotatedFace2</field></block></value><value name="Translation"><block type="lists_create_with" id="J:ZTQ1|9T6%9z7TJ7:FO"><mutation items="3"></mutation><value name="ADD0"><block type="math_arithmetic" id="VG~NQW8nP=%7CtG2=gI"><field name="OP">DIVIDE</field><value name="A"><block type="variables_get" id="7+_,j}Q|qbBfT2>ht:]M"><field name="VAR" id="2j#UKo}(~;^`c8a2]Lzc">size</field></block></value><value name="B"><block type="math_number" id="#m~KQ}hO3[z%L1,rIpn("><field name="NUM">2</field></block></value></block></value><value name="ADD1"><block type="math_arithmetic" id="1]!z?HuLlev[p:#,*j4p"><field name="OP">DIVIDE</field><value name="A"><block type="variables_get" id=")+^5N$3M}vN._mD+9!5]"><field name="VAR" id="2j#UKo}(~;^`c8a2]Lzc">size</field></block></value><value name="B"><block type="math_number" id="KvA*!7Z$*;nPC>3v=ROn"><field name="NUM">2</field></block></value></block></value><value name="ADD2"><block type="math_number" id="H@LB#kOa*}w16b0wB{z."><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="3qz5;6XZHm!Q!w)_M=S:"><field name="VAR" id="a%e_#NZ$KjnM<K(j}`:)">faces</field><value name="VALUE"><block type="lists_create_with" id="^xO$SBY5JW>6i(,mZ`m;"><mutation items="2"></mutation><value name="ADD0"><block type="variables_get" id="Ziq.?TrMoOhN8RH|4*I9"><field name="VAR" id="ItXu:Dn?)s,v)b.oMN=?">face1</field></block></value><value name="ADD1"><block type="variables_get" id="hO^WqtAH/=Uo(/3D$,3r"><field name="VAR" id="J!fA.:+w-ywlhH2i*Aq4">translatedFace2</field></block></value></block></value><next><block type="variables_set" id="Q%DI?Zw.jK(iN.:_4w)Z"><field name="VAR" id="^/xo7LZ:%?M._xp*+:5:">shell</field><value name="VALUE"><block type="bitbybit.occt.shapes.shell.sewFaces" id="!6eU}2B,P-!n`9z6N[%H"><value name="Shapes"><block type="variables_get" id="xh=Cq{`j5t1#d3*,4=sn"><field name="VAR" id="a%e_#NZ$KjnM<K(j}`:)">faces</field></block></value><value name="Tolerance"><block type="math_number" id="*j$}Bf|1!OY[8kP[hf:["><field name="NUM">0.0000001</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="M^w)+3T>7iVS>/F)HhgR"><value name="Entity"><block type="variables_get" id="?{Vk*8@O!F@2|@xp1]P="><field name="VAR" id="^/xo7LZ:%?M._xp*+:5:">shell</field></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs for creating faces, shells, and transformations
const { SquareDto, SewDto, RotateDto, TranslateDto } = Bit.Inputs.OCCT;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
type TopoDSShellPointer = Bit.Inputs.OCCT.TopoDSShellPointer;
// Get access to OCCT modules and utility functions
const { face, shell, shape } = bitbybit.occt.shapes;
const { transforms } = bitbybit.occt;
// Define the main function to create a simple shell from two faces
const start = async () => {
// Define the size for both square faces
const size = 5;
// Create first square face at origin
const face1Options = new SquareDto();
face1Options.size = size;
face1Options.center = [0, 0, 0] as Point3;
face1Options.direction = [0, 1, 0] as Vector3; // Y-up orientation
const face1 = await face.createSquareFace(face1Options);
// Create second square face (initially identical to first)
const face2Options = new SquareDto();
face2Options.size = size;
face2Options.center = [0, 0, 0] as Point3;
face2Options.direction = [0, 1, 0] as Vector3;
const face2 = await face.createSquareFace(face2Options);
// Rotate the second face 90 degrees around Z-axis to create perpendicular orientation
const rotateOptions = new RotateDto<TopoDSFacePointer>();
rotateOptions.shape = face2;
rotateOptions.axis = [0, 0, 1] as Vector3; // Z-axis
rotateOptions.angle = 90; // 90 degrees
const rotatedFace2 = await transforms.rotate(rotateOptions);
// Translate the rotated face to share an edge with the first face
const translateOptions = new TranslateDto<TopoDSFacePointer>();
translateOptions.shape = rotatedFace2;
translateOptions.translation = [size / 2, size / 2, 0] as Vector3;
const translatedFace2 = await transforms.translate(translateOptions);
// Create array of faces to sew together
const faces = [face1, translatedFace2];
// Sew the faces together to create a shell
const sewOptions = new SewDto<TopoDSFacePointer>(faces);
sewOptions.tolerance = 1e-7; // Very tight tolerance for precise sewing
const resultShell = await shell.sewFaces(sewOptions);
// Verify that we created a shell (not just individual faces)
const shapeType = await shape.getShapeType({ shape: resultShell });
console.log('Shell shape type:', shapeType); // Should output "shell"
// Draw the resulting shell
bitbybit.draw.drawAnyAsync({
entity: resultShell
});
}
// Execute the function
start();
The workflow demonstrates several key concepts:
- Face Creation: Two identical square faces are created with the same dimensions and orientation.
- Geometric Transformation: The second face is rotated 90 degrees and then translated to position it perpendicular to the first face, sharing a common edge.
- Sewing Process: The
sewFacesoperation identifies the shared edge and creates topological connections between the faces. - Validation: The
getShapeTypefunction confirms that the result is indeed a shell rather than separate faces.
This simple example shows how shells maintain the relationship between connected faces, creating a unified geometric entity that can be used in further operations.
Advanced Shell Example: Creating a Closed Solid
This more sophisticated example demonstrates how to create a complex shell from multiple faces that form a closed surface, which can then be converted into a solid. We'll construct a cylindrical shape by creating circular faces and an extruded cylindrical surface, then sew them together to form a closed shell.
While this cylindrical solid can be constructed in Bitbybit using the simple solid cylinder command, this example is created for demonstration purposes to show the face-based shell construction process. Understanding face-based construction is valuable for creating complex custom geometries that cannot be easily generated using primitive solid operations.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"24a8eb2d1bb86800": {
"id": "24a8eb2d1bb86800",
"name": "bitbybit.occt.shapes.wire.createCircleWire",
"customName": "circle wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 5,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
-48.46557798089094,
444.0530981101432
]
},
"e2fe4a17d104263b": {
"id": "e2fe4a17d104263b",
"name": "bitbybit.occt.operations.extrude",
"customName": "extrude",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
1,
0
]
},
"inputs": {
"direction": {
"connections": [
{
"node": "38ae3cb83708e9b9",
"output": "result",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "24a8eb2d1bb86800",
"output": "result",
"data": {}
}
]
}
},
"position": [
1135.7636928118839,
431.5419722022928
]
},
"38ae3cb83708e9b9": {
"id": "38ae3cb83708e9b9",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 5,
"z": 0
},
"inputs": {},
"position": [
-49.40205840336434,
1148.597010032251
]
},
"63b9ee355fe2b33c": {
"id": "63b9ee355fe2b33c",
"name": "bitbybit.occt.shapes.face.createFaceFromWire",
"customName": "face from wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"planar": true
},
"inputs": {
"shape": {
"connections": [
{
"node": "24a8eb2d1bb86800",
"output": "result",
"data": {}
}
]
}
},
"position": [
1131.4753008017224,
762.9304737852682
]
},
"4ddaed3adf9fb160": {
"id": "4ddaed3adf9fb160",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
0,
0,
0
]
},
"inputs": {
"translation": {
"connections": [
{
"node": "38ae3cb83708e9b9",
"output": "result",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "63b9ee355fe2b33c",
"output": "result",
"data": {}
}
]
}
},
"position": [
1567.3701297241523,
1107.143034712424
]
},
"9de0d30cdc7a077a": {
"id": "9de0d30cdc7a077a",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "4ddaed3adf9fb160",
"output": "result",
"data": {}
},
{
"node": "e2fe4a17d104263b",
"output": "result",
"data": {}
},
{
"node": "63b9ee355fe2b33c",
"output": "result",
"data": {}
}
]
}
},
"position": [
2106.2124886144506,
466.8004093457119
]
},
"4453f9eb5b5c9ad4": {
"id": "4453f9eb5b5c9ad4",
"name": "bitbybit.occt.shapes.shell.sewFaces",
"customName": "sew faces",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7
},
"inputs": {
"shapes": {
"connections": [
{
"node": "9de0d30cdc7a077a",
"output": "list",
"data": {}
}
]
}
},
"position": [
2491.6266582166304,
424.8624162806204
]
},
"290d349f77f552fb": {
"id": "290d349f77f552fb",
"name": "bitbybit.occt.shapes.solid.fromClosedShell",
"customName": "from closed shell",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "4453f9eb5b5c9ad4",
"output": "result",
"data": {}
}
]
}
},
"position": [
3137.9526006441383,
425.24534627981524
]
},
"bf4fb17f76715d55": {
"id": "bf4fb17f76715d55",
"name": "bitbybit.occt.shapes.shape.getShapeType",
"customName": "get shape type",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "4453f9eb5b5c9ad4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2916.2482400937824,
804.092475293075
]
},
"e210748d669d414d": {
"id": "e210748d669d414d",
"name": "bitbybit.occt.shapes.shape.getShapeType",
"customName": "get shape type",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "290d349f77f552fb",
"output": "result",
"data": {}
}
]
}
},
"position": [
3585.2277817058366,
422.99279863437056
]
},
"f22dfd3ca265caad": {
"id": "f22dfd3ca265caad",
"name": "bitbybit.previewData",
"customName": "preview data",
"data": {
"previewJSONControl": "[\n \"shell\"\n]"
},
"inputs": {
"data": {
"connections": [
{
"node": "bf4fb17f76715d55",
"output": "result",
"data": {}
}
]
}
},
"position": [
3392.7378669946693,
843.4021999285142
]
},
"16972d5ae04ba501": {
"id": "16972d5ae04ba501",
"name": "bitbybit.previewData",
"customName": "preview data",
"data": {
"previewJSONControl": "[\n \"solid\"\n]"
},
"inputs": {
"data": {
"connections": [
{
"node": "e210748d669d414d",
"output": "result",
"data": {}
}
]
}
},
"position": [
4001.0771450618367,
462.5634892963901
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="B5JBrj|E*pK^k&TqWCb4">radius</variable><variable id="OE*|dE{}rjg]L?Fy7+QJ">height</variable><variable id=":]h8dV2oR;hN0y)9A<3R">circleWire</variable><variable id="Q6D$-F1&d%V?U1G|e!Rt">extrusionVector</variable><variable id="P>Ip[BkP4(K+vJI3WVMt">cylindricalSurface</variable><variable id="NJ<l>Q5X.6w~iA?5*wFd">bottomFace</variable><variable id="dh.(%cL!g2x>Sj}eX6~z">topFace</variable><variable id="+QD=Cf@I6:Qu-]f4d8+e">faces</variable><variable id=">+H$BHS)d|n@&+r{/pY?">shell</variable><variable id="^4)Q>WP-HQHN[y!V[jL^">solid</variable></variables><block type="variables_set" id="V[cKGTa<bnl?`z[pO2C}" x="-247" y="-398"><field name="VAR" id="B5JBrj|E*pK^k&TqWCb4">radius</field><value name="VALUE"><block type="math_number" id="M)RCt%v-mJb<z9?;*YJ!"><field name="NUM">5</field></block></value><next><block type="variables_set" id="d0GKQR}*pV@qMKZ1l<PO"><field name="VAR" id="OE*|dE{}rjg]L?Fy7+QJ">height</field><value name="VALUE"><block type="math_number" id="U5A8+sBu2dgs{.dN[vdE"><field name="NUM">5</field></block></value><next><block type="variables_set" id="@UPq@5Z7Wts|EGHA)3`?"><field name="VAR" id=":]h8dV2oR;hN0y)9A<3R">circleWire</field><value name="VALUE"><block type="bitbybit.occt.shapes.wire.createCircleWire" id="i]Qe:5xNlG],Z^B`H8Q@"><value name="Radius"><block type="variables_get" id="^=6ggcqE3L]/;lkzf{Eq"><field name="VAR" id="B5JBrj|E*pK^k&TqWCb4">radius</field></block></value><value name="Center"><block type="lists_create_with" id="6xOIb%Kl}6V>Mm>Bd9tC"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="aD5#MeCCTQU>;`$],6-)"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="@7=L.hQT^g%5-5:p<=3S"><field name="NUM">0</field></block></value><value name="ADD2"><block type="math_number" id="=tgjYpY/u#)J#bNBZ+YI"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="lists_create_with" id="uyM$f>2w1iX_gzP^gKN1"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id="t9^]r{lPqAv{wHPEaM+f"><field name="NUM">0</field></block></value><value name="ADD1"><block type="math_number" id="@JJyDw@l+0(5F-fzjy@["><field name="NUM">1</field></block></value><value name="ADD2"><block type="math_number" id="3`k(EzLT$K5}!k]9@m@4"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="g*zH)3}J~nW}z}S+:qR>"><field name="VAR" id="Q6D$-F1&d%V?U1G|e!Rt">extrusionVector</field><value name="VALUE"><block type="lists_create_with" id="a_!SZ#eXj7YBE%b/H1%I"><mutation items="3"></mutation><value name="ADD0"><block type="math_number" id=")@K!QaWWI1b@%B:?RdA7"><field name="NUM">0</field></block></value><value name="ADD1"><block type="variables_get" id="C5*8Hm^@f2O.{nAV0~|m"><field name="VAR" id="OE*|dE{}rjg]L?Fy7+QJ">height</field></block></value><value name="ADD2"><block type="math_number" id="nON/5{e3o9!K;#z>$+^k"><field name="NUM">0</field></block></value></block></value><next><block type="variables_set" id="5iV8Ld)L|@Nk/3CX]!KG"><field name="VAR" id="P>Ip[BkP4(K+vJI3WVMt">cylindricalSurface</field><value name="VALUE"><block type="bitbybit.occt.operations.extrude" id="VpKm,uY~Yj|(;*l8e,DP"><value name="Shape"><block type="variables_get" id="p>8Y@|t$2-H*6UO:(&b["><field name="VAR" id=":]h8dV2oR;hN0y)9A<3R">circleWire</field></block></value><value name="Direction"><block type="variables_get" id="YX+3yJ+TCOZ;w#Z<l=C$"><field name="VAR" id="Q6D$-F1&d%V?U1G|e!Rt">extrusionVector</field></block></value></block></value><next><block type="variables_set" id="mR@zZ[-=V@d$%+!P{G9L"><field name="VAR" id="NJ<l>Q5X.6w~iA?5*wFd">bottomFace</field><value name="VALUE"><block type="bitbybit.occt.shapes.face.createFaceFromWire" id="3?MNw%*:LZ2G2jh[zf2T"><value name="Shape"><block type="variables_get" id="`Q,Jy%SgTGYbXk5fEMx_"><field name="VAR" id=":]h8dV2oR;hN0y)9A<3R">circleWire</field></block></value><value name="Planar"><block type="logic_boolean" id="k_lmyL]`}^mLRKhI{jF("><field name="BOOL">TRUE</field></block></value></block></value><next><block type="variables_set" id="1XnuS,kLl]hJ2>lEY*(C"><field name="VAR" id="dh.(%cL!g2x>Sj}eX6~z">topFace</field><value name="VALUE"><block type="bitbybit.occt.transforms.translate" id="YnP>-qFQZMR;)UG^9I,8"><value name="Shape"><block type="variables_get" id="QNj;*A%8B2]!P[%J}VCD"><field name="VAR" id="NJ<l>Q5X.6w~iA?5*wFd">bottomFace</field></block></value><value name="Translation"><block type="variables_get" id="2lT[1/Xh=1YZ<MjLbI~;"><field name="VAR" id="Q6D$-F1&d%V?U1G|e!Rt">extrusionVector</field></block></value></block></value><next><block type="variables_set" id="p_6D=;q$>P$8S)]=?lq"><field name="VAR" id="+QD=Cf@I6:Qu-]f4d8+e">faces</field><value name="VALUE"><block type="lists_create_with" id="j<Hu$*GKqI4TZr9Y>pf]"><mutation items="3"></mutation><value name="ADD0"><block type="variables_get" id="o!9N@>F[qX)6S9?v#Jnw"><field name="VAR" id="dh.(%cL!g2x>Sj}eX6~z">topFace</field></block></value><value name="ADD1"><block type="variables_get" id="/Q>BLMpZQVD~S]=P_g-m"><field name="VAR" id="P>Ip[BkP4(K+vJI3WVMt">cylindricalSurface</field></block></value><value name="ADD2"><block type="variables_get" id="j,!YMM:C2R1+hS2:Qx@="><field name="VAR" id="NJ<l>Q5X.6w~iA?5*wFd">bottomFace</field></block></value></block></value><next><block type="variables_set" id="d.2eJ36x!~f+#T,G7Lhp"><field name="VAR" id=">+H$BHS)d|n@&+r{/pY?">shell</field><value name="VALUE"><block type="bitbybit.occt.shapes.shell.sewFaces" id="q-|zf%mWWg|>~>z[fRrJ"><value name="Shapes"><block type="variables_get" id="wGS5YFKr):&T9E~n}Grf"><field name="VAR" id="+QD=Cf@I6:Qu-]f4d8+e">faces</field></block></value><value name="Tolerance"><block type="math_number" id="aH/.]w=/b^0<8;q2;FE,"><field name="NUM">1e-7</field></block></value></block></value><next><block type="variables_set" id=")+1(AzWAaQ&]gn<ZP[}7"><field name="VAR" id="^4)Q>WP-HQHN[y!V[jL^">solid</field><value name="VALUE"><block type="bitbybit.occt.shapes.solid.fromClosedShell" id=":F{?]J[Cb:2?8JZ,^K3C"><value name="Shape"><block type="variables_get" id="qLrS<CJ7v!;$ZGRg_Dc!"><field name="VAR" id=">+H$BHS)d|n@&+r{/pY?">shell</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="]p5tl,>d,c2#Th{FLE3C"><value name="Entity"><block type="variables_get" id="7-T1g>gF.b>PqA^[>iE9"><field name="VAR" id="^4)Q>WP-HQHN[y!V[jL^">solid</field></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs for creating complex geometries
const { CircleDto, FaceFromWireDto, ShapeDto, SewDto, ExtrudeDto, TranslateDto } = Bit.Inputs.OCCT;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
type TopoDSShellPointer = Bit.Inputs.OCCT.TopoDSShellPointer;
// Get access to OCCT modules and utility functions
const { wire, face, shell, solid, shape } = bitbybit.occt.shapes;
const { operations, transforms } = bitbybit.occt;
// Define the main function to create a complex shell and convert to solid
const start = async () => {
// Define geometric parameters
const radius = 5;
const height = 5;
// Step 1: Create base circle wire
const circleOptions = new CircleDto();
circleOptions.radius = radius;
circleOptions.center = [0, 0, 0] as Point3;
circleOptions.direction = [0, 1, 0] as Vector3; // Y-up orientation
const circleWire = await wire.createCircleWire(circleOptions);
// Step 2: Create extrusion vector for cylindrical surface
const extrusionVector: Vector3 = [0, height, 0];
// Step 3: Create cylindrical surface by extruding the circle wire
const extrudeOptions = new ExtrudeDto<TopoDSWirePointer>();
extrudeOptions.shape = circleWire;
extrudeOptions.direction = extrusionVector;
const cylindricalSurface = await operations.extrude(extrudeOptions);
// Step 4: Create bottom face from the circle wire
const bottomFaceOptions = new FaceFromWireDto<TopoDSWirePointer>();
bottomFaceOptions.shape = circleWire;
bottomFaceOptions.planar = true; // Ensure flat circular face
const bottomFace = await face.createFaceFromWire(bottomFaceOptions);
// Step 5: Create top face by translating bottom face
const translateOptions = new TranslateDto<TopoDSFacePointer>();
translateOptions.shape = bottomFace;
translateOptions.translation = extrusionVector;
const topFace = await transforms.translate(translateOptions);
// Step 6: Collect all faces that will form the closed shell
const faces = [topFace, cylindricalSurface, bottomFace];
// Step 7: Sew faces together to create a closed shell
const sewOptions = new SewDto<TopoDSFacePointer>(faces);
sewOptions.tolerance = 1e-7; // High precision for closed shell
const closedShell = await shell.sewFaces(sewOptions);
// Step 8: Convert closed shell to solid
const solidOptions = new ShapeDto<TopoDSShellPointer>();
solidOptions.shape = closedShell;
const cylinderSolid = await solid.fromClosedShell(solidOptions);
// Step 9: Verify the shape types
const shellType = await shape.getShapeType({ shape: closedShell });
const solidType = await shape.getShapeType({ shape: cylinderSolid });
console.log('Shell type:', shellType); // Should output "shell"
console.log('Solid type:', solidType); // Should output "solid"
// Step 10: Draw the final solid
bitbybit.draw.drawAnyAsync({
entity: cylinderSolid
});
}
// Execute the function
start();
This advanced example demonstrates several sophisticated concepts:
The Construction Process
-
Base Geometry Creation: We start by creating a circular wire that serves as the foundation for our cylindrical shape.
-
Surface Generation: The circular wire is extruded to create the cylindrical surface that will form the sides of our shape.
-
End Cap Creation: Two circular faces are created - one at the bottom (from the original circle wire) and one at the top (by translating the bottom face upward).
-
Shell Assembly: All three faces (bottom, top, and cylindrical surface) are sewn together using the
sewFacesoperation to create a closed shell. -
Solid Conversion: The closed shell is converted into a solid using
fromClosedShell, which validates that the shell properly encloses a volume.
Key Advantages of This Workflow
Topological Validity: By creating shells first and then converting to solids, we ensure that the resulting geometry has proper topological relationships between faces, edges, and vertices.
Error Detection: If the shell is not properly closed or has topological issues, the fromClosedShell operation will fail.
Geometric Flexibility: This approach allows for complex surface creation that might be difficult to achieve with direct solid modeling operations.
Intermediate Inspection: You can examine and validate the shell before converting it to a solid, making debugging easier in complex workflows.
Making geometry from faces is usually way faster than performing boolean operations such as union or difference. When designing complex geometries, it pays to think in terms of faces and shell construction rather than relying heavily on boolean operations. This face-based approach not only provides better performance but also gives you more precise control over the final geometry and better error handling for invalid operations.
This tutorial demonstrates how shells serve as a crucial intermediate representation in OCCT, bridging the gap between individual faces and complete solid geometries while providing powerful tools for surface-based modeling.



