Extruding Wires And Faces
Extruding a Wire
Extrusion is a fundamental 3D modeling operation that creates a three-dimensional shape by extending a profile (a wire) along a specified vector. Imagine taking a flat shape and pushing it through space to give it depth; that's the essence of extrusion. This technique is widely used for creating a vast array of objects, from simple geometric solids to complex mechanical parts and architectural elements.
In this tutorial, we'll guide you through the process of creating an extruded shape. We will start by defining a 2D star-shaped wire, apply a 2D fillet to round its corners, and then extrude this modified wire along a vector to form a 3D object. We'll demonstrate this process using Rete, Blockly, and TypeScript, providing clear examples for each environment.
The key parameters for an extrusion operation typically include:
- The Profile (Wire): This is the shape that will be extruded. It can be any closed or open wire, such as a circle, polygon, or a custom-defined curve or polyline.
- The Extrusion Vector: This defines the direction and distance (magnitude) of the extrusion. The profile is swept along this vector.
- Solid or Shell: When you extrude the wire you create a shell shape. If you extrude face you create solid.
By understanding extrusion, you gain a powerful tool for your 3D modeling toolkit.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"7c920baffd91d425": {
"id": "7c920baffd91d425",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"numRays": 7,
"outerRadius": 7,
"innerRadius": 4,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
110.734375,
360.171875
]
},
"a3ad01ccca577e86": {
"id": "a3ad01ccca577e86",
"name": "bitbybit.occt.operations.extrude",
"customName": "extrude",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
1,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "27e9c145d5e43cd0",
"output": "result",
"data": {}
}
]
},
"direction": {
"connections": [
{
"node": "58f71d7c11226693",
"output": "result",
"data": {}
}
]
}
},
"position": [
1070.1244775692053,
638.622822251194
]
},
"27e9c145d5e43cd0": {
"id": "27e9c145d5e43cd0",
"name": "bitbybit.occt.fillets.fillet2d",
"customName": "fillet 2d",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.5
},
"inputs": {
"shape": {
"connections": [
{
"node": "7c920baffd91d425",
"output": "result",
"data": {}
}
]
}
},
"position": [
490.85570951639164,
357.61402718044616
]
},
"58f71d7c11226693": {
"id": "58f71d7c11226693",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 3,
"z": 0
},
"inputs": {
"y": {
"connections": [
{
"node": "16fef8b5633bf2fa",
"output": "result",
"data": {}
}
]
}
},
"position": [
491.9697917949816,
908.010548409781
]
},
"16fef8b5633bf2fa": {
"id": "16fef8b5633bf2fa",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 1,
"max": 6,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 2.8
},
"inputs": {},
"position": [
-418.6465475549992,
986.9008502987708
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="O=}%oo4UY.:NKu%Q}yay">height</variable></variables><block type="variables_set" id="n=)tV#J1]nAGE6_mwd02" x="-164" y="-108"><field name="VAR" id="O=}%oo4UY.:NKu%Q}yay">height</field><value name="VALUE"><block type="math_number" id=".CUeZB`hR{eSYKDoWUxx"><field name="NUM">4</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="BWkO[mpA[k%*`WcS0D-I"><value name="Entity"><block type="bitbybit.occt.operations.extrude" id="j`T:J*vKYFU35K/G:T`P"><value name="Shape"><block type="bitbybit.occt.fillets.fillet2d" id="3*A4(63w-4nh8:L*Qu+^"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createStarWire" id="wd8Oy:_[On{gYJ0pulHD"><value name="Center"><block type="bitbybit.point.pointXYZ" id="wvW[0UbV#2,N0{g1W:k5"><value name="X"><block type="math_number" id="|v{~5Apf,$iw[!8M+j,p"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="yi@*Gy-RJk*6$GKy~QH%"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="+x@^zj9z{O.0DYNjt.vz"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="sXr=wr?W:$2gb8zwv372"><value name="X"><block type="math_number" id="$b$^Ef6gW2ji?N`9@k7!"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="2@MY+T9|kJdqQU@#kuQS"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="E[D~xhub@Q]U2OxoK9-n"><field name="NUM">0</field></block></value></block></value><value name="NumRays"><block type="math_number" id="HoCQLqA(VF0!Yo-6hn=S"><field name="NUM">7</field></block></value><value name="OuterRadius"><block type="math_number" id="[Ah]O653Sf!J0r@Oy$h9"><field name="NUM">7</field></block></value><value name="InnerRadius"><block type="math_number" id="$Te~M.)q`X%oKnoexS|1"><field name="NUM">4</field></block></value><value name="OffsetOuterEdges"><block type="math_number" id="Hsgkv0GFXQnSCmeCDuS]"><field name="NUM">0</field></block></value><value name="Half"><block type="logic_boolean" id="/W#wmKV~q*bmYN+8BU+X"><field name="BOOL">FALSE</field></block></value></block></value><value name="Radius"><block type="math_number" id="XlA[-vjKq#m5D8rJZR~o"><field name="NUM">0.5</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="CV2g23bS~Fz0=!)#@5/A"><value name="X"><block type="math_number" id="`J?3jCiN{?!q%+cXe~2H"><field name="NUM">0</field></block></value><value name="Y"><block type="variables_get" id=":t=8xX70DSc9h);qH4z7"><field name="VAR" id="O=}%oo4UY.:NKu%Q}yay">height</field></block></value><value name="Z"><block type="math_number" id="$1`NZ5C%_29C(2o]9z#r"><field name="NUM">0</field></block></value></block></value></block></value></block></next></block></xml>
// Import the 'wire' module for creating wire shapes from the OCCT (OpenCASCADE Technology) library.
const { wire } = bitbybit.occt.shapes;
// Import 'fillets' and 'operations' modules for performing filleting and extrusion operations on OCCT shapes.
const { fillets, operations } = bitbybit.occt;
// Import Data Transfer Objects (DTOs) for configuring star creation, filleting, and extrusion.
// DTOs are used to pass parameters to the respective functions.
const { StarDto, FilletDto, ExtrudeDto } = Bit.Inputs.OCCT;
// Define a type alias for a pointer to a TopoDS_Wire, which is an OCCT data structure representing a wire.
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
// Define an asynchronous function named 'start' which will contain the main logic for creating and drawing the shape.
// The 'async' keyword allows the use of 'await' for operations that might take time, like geometry creation.
const start = async () => {
// Define a constant 'height' for the extrusion operation.
const height = 4;
// Create a new StarDto instance to configure the properties of a star-shaped wire.
const starOpt = new StarDto();
// Set the inner radius of the star.
starOpt.innerRadius = 4;
// Set the outer radius of the star.
starOpt.outerRadius = 7;
// Asynchronously create the star-shaped wire using the configured options.
// The 'await' keyword pauses execution until the wire creation is complete.
// Bitbybit runs such CAD operations in the worker thread, which doesn't block UI
// and is usually faster.
const star = await wire.createStarWire(starOpt);
// Create a new FilletDto instance to configure a 2D fillet operation.
// The generic type <TopoDSWirePointer> specifies that this fillet will be applied to a wire.
const filletOpt = new FilletDto<TopoDSWirePointer>();
// Set the shape to be filleted to the previously created star wire.
filletOpt.shape = star;
// Set the radius for the fillet (rounding of corners).
filletOpt.radius = 0.5;
// Asynchronously apply the 2D fillet to the star wire.
const roundedStar = await fillets.fillet2d(filletOpt);
// Create a new ExtrudeDto instance to configure an extrusion operation.
// The generic type <TopoDSWirePointer> specifies that a wire will be extruded.
const extrudeOpt = new ExtrudeDto<TopoDSWirePointer>();
// Set the shape to be extruded to the previously created rounded star wire.
extrudeOpt.shape = roundedStar;
// Set the direction and magnitude of the extrusion as a 3D vector [x, y, z].
// Here, it extrudes along the Y-axis by the value of 'height'.
extrudeOpt.direction = [0, height, 0];
// Asynchronously perform the extrusion operation on the rounded star wire.
const extrudedRoundStar = await operations.extrude(extrudeOpt);
// Asynchronously draw the final extruded shape in the 3D scene.
// 'entity' specifies the shape to be drawn.
bitbybit.draw.drawAnyAsync({ entity: extrudedRoundStar });
}
// Call the 'start' function to execute the script.
start();
Extruding a Face
In addition to extruding wires (which typically create shells or open-ended shapes), you can also extrude faces. A face in this context is a bounded surface, often created from one or more closed wires. When a face is extruded, the operation effectively sweeps this surface along the extrusion vector, creating a closed volumetric body, or a solid.
This is a crucial distinction:
- Wire Extrusion: Generally results in a shell (a collection of connected faces without volume, like a pipe).
- Face Extrusion: Results in a solid (a shape with enclosed volume, like a solid bar).
In the following examples, we first construct a complex wire, then create a planar face from this wire, and finally extrude this face to produce a solid 3D object. This demonstrates a common workflow: defining a profile as a face and then giving it depth to create a solid part.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"a3ad01ccca577e86": {
"id": "a3ad01ccca577e86",
"name": "bitbybit.occt.operations.extrude",
"customName": "extrude",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
1,
0
]
},
"inputs": {
"direction": {
"connections": [
{
"node": "58f71d7c11226693",
"output": "result",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "83b8300f86a7d1c6",
"output": "result",
"data": {}
}
]
}
},
"position": [
885.5203527172653,
551.3241854977023
]
},
"58f71d7c11226693": {
"id": "58f71d7c11226693",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 3,
"z": 0
},
"inputs": {
"y": {
"connections": [
{
"node": "16fef8b5633bf2fa",
"output": "result",
"data": {}
}
]
}
},
"position": [
380.20906256341385,
785.7649077285179
]
},
"16fef8b5633bf2fa": {
"id": "16fef8b5633bf2fa",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 1,
"max": 6,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 1.5
},
"inputs": {},
"position": [
-663.9156894269311,
863.0508723168588
]
},
"3bb14d673fa0d00b": {
"id": "3bb14d673fa0d00b",
"name": "bitbybit.occt.shapes.wire.createHeartWire",
"customName": "heart wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"rotation": 0,
"sizeApprox": 5
},
"inputs": {},
"position": [
-532.6021201120332,
340.9870613060303
]
},
"9b4a825147ce5bc0": {
"id": "9b4a825147ce5bc0",
"name": "bitbybit.occt.shapes.wire.createZigZagBetweenTwoWires",
"customName": "zig zag between two wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"nrZigZags": 31,
"inverse": true,
"divideByEqualDistance": true,
"zigZagsPerEdge": true
},
"inputs": {
"wire2": {
"connections": [
{
"node": "3bb14d673fa0d00b",
"output": "result",
"data": {}
}
]
},
"wire1": {
"connections": [
{
"node": "3102582b6246e51c",
"output": "result",
"data": {}
}
]
}
},
"position": [
-84.63233896640459,
106.29897050725572
]
},
"3102582b6246e51c": {
"id": "3102582b6246e51c",
"name": "bitbybit.occt.shapes.wire.createHeartWire",
"customName": "heart wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"rotation": 0,
"sizeApprox": 7
},
"inputs": {},
"position": [
-513.0810817981617,
-69.32154536997916
]
},
"83b8300f86a7d1c6": {
"id": "83b8300f86a7d1c6",
"name": "bitbybit.occt.shapes.face.createFaceFromWire",
"customName": "face from wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"planar": true
},
"inputs": {
"shape": {
"connections": [
{
"node": "9b4a825147ce5bc0",
"output": "result",
"data": {}
}
]
}
},
"position": [
358.5062775790989,
214.32449710401428
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="O=}%oo4UY.:NKu%Q}yay">height</variable></variables><block type="variables_set" id="n=)tV#J1]nAGE6_mwd02" x="-164" y="-108"><field name="VAR" id="O=}%oo4UY.:NKu%Q}yay">height</field><value name="VALUE"><block type="math_number" id=".CUeZB`hR{eSYKDoWUxx"><field name="NUM">4</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="BWkO[mpA[k%*`WcS0D-I"><value name="Entity"><block type="bitbybit.occt.operations.extrude" id="j`T:J*vKYFU35K/G:T`P"><value name="Shape"><block type="bitbybit.occt.shapes.face.createFaceFromWire" id="~MqUvomSaT`;dcG=mp3n"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createZigZagBetweenTwoWires" id="((#sB5eK#*)fre?XCiS1"><value name="Wire1"><block type="bitbybit.occt.shapes.wire.createHeartWire" id="M}Hzz3-@qs281ixM:b4;"><value name="Center"><block type="bitbybit.point.pointXYZ" id="E*dbwa4#ejJ61/z}o*@r"><value name="X"><block type="math_number" id="bAA/C20lsaTd6+5$0q{A"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="p+BfDHp/D}mx-Aq236f*"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="2FWw:%Kbx:)+OPD].D^Y"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="WJG-l3{rJGr+DC!=~q.v"><value name="X"><block type="math_number" id=")R;Fyg^zN|5aBLa)eyyD"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="a;Z3AM2RyYV6O;4/pbJ7"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="$C{Y-qBvs48ID0~#88.x"><field name="NUM">0</field></block></value></block></value><value name="Rotation"><block type="math_number" id="U^S-(c_B~U{]C6ms*/M:"><field name="NUM">0</field></block></value><value name="SizeApprox"><block type="math_number" id="GU$:nsWK9+XoD#lx)0?:"><field name="NUM">7</field></block></value></block></value><value name="Wire2"><block type="bitbybit.occt.shapes.wire.createHeartWire" id="FfszF?290p*]@W8S`.g]"><value name="Center"><block type="bitbybit.point.pointXYZ" id="X~BydmfQ~z3f`O%jEq/."><value name="X"><block type="math_number" id="f4v6!jgMTnI`:5Masf(|"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="Y-mc@bXZN/+vA?@7X`]D"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="5u$fAZG63sB7+lpuMQ`="><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="YVTz(J2X2XPrVY^ZPjtO"><value name="X"><block type="math_number" id="c(1AVaX71hEjenj1EhBh"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="%9Ki22wb+::TD^G:blhw"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="pL$cd8Of#BkaIsir;U?O"><field name="NUM">0</field></block></value></block></value><value name="Rotation"><block type="math_number" id="96-ksFf_Qae!X4g@L}r5"><field name="NUM">0</field></block></value><value name="SizeApprox"><block type="math_number" id="G~`i7E`P[SXknyij3k|f"><field name="NUM">5</field></block></value></block></value><value name="NrZigZags"><block type="math_number" id="a(yMcvEU8CgDsvOsWCy6"><field name="NUM">20</field></block></value><value name="Inverse"><block type="logic_boolean" id="%e|;H1?[(7LDZJP8}N`3"><field name="BOOL">FALSE</field></block></value><value name="DivideByEqualDistance"><block type="logic_boolean" id="qK|3eLsdfKa/O#y!x:$%"><field name="BOOL">FALSE</field></block></value><value name="ZigZagsPerEdge"><block type="logic_boolean" id="?yarMdN[~(#$KvtAw,i#"><field name="BOOL">TRUE</field></block></value></block></value><value name="Planar"><block type="logic_boolean" id="uMD;Ily=*r]w$qG`OO+-"><field name="BOOL">TRUE</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="CV2g23bS~Fz0=!)#@5/A"><value name="X"><block type="math_number" id="`J?3jCiN{?!q%+cXe~2H"><field name="NUM">0</field></block></value><value name="Y"><block type="variables_get" id=":t=8xX70DSc9h);qH4z7"><field name="VAR" id="O=}%oo4UY.:NKu%Q}yay">height</field></block></value><value name="Z"><block type="math_number" id="$1`NZ5C%_29C(2o]9z#r"><field name="NUM">0</field></block></value></block></value></block></value></block></next></block></xml>
const { wire, face } = bitbybit.occt.shapes;
const { fillets, operations } = bitbybit.occt;
const { FilletDto, ExtrudeDto, Heart2DDto, ZigZagBetweenTwoWiresDto, FaceFromWireDto } = Bit.Inputs.OCCT;
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
const start = async () => {
const height = 4;
const heartOpt = new Heart2DDto();
heartOpt.sizeApprox = 7;
const heart1 = await wire.createHeartWire(heartOpt);
heartOpt.sizeApprox = 5;
const heart2 = await wire.createHeartWire(heartOpt);
const zigZagOpt = new ZigZagBetweenTwoWiresDto(heart1, heart2, 31);
const zigZagWire = await wire.createZigZagBetweenTwoWires(zigZagOpt);
const faceFromWireOpt = new FaceFromWireDto<TopoDSWirePointer>(zigZagWire, true);
const zigZagFace = await face.createFaceFromWire(faceFromWireOpt);
const extrudeOpt = new ExtrudeDto<TopoDSFacePointer>();
extrudeOpt.shape = zigZagFace;
extrudeOpt.direction = [0, height, 0];
const extrudedZigZag = await operations.extrude(extrudeOpt);
bitbybit.draw.drawAnyAsync({ entity: extrudedZigZag });
}
start();
With these examples, you've learned the basics of creating extruded 3D shapes from both 2D wire profiles (resulting in shells) and 2D faces (resulting in solids). This operation is a cornerstone of many CAD workflows, allowing for the creation of diverse geometries.
You can also extrude shells (shapes consisting out of multiple faces).
Feel free to experiment with different base wire and face shapes (e.g., circles, rectangles, polygons, or more complex custom profiles) and vary the extrusion vector (both direction and magnitude). You can also explore combining extrusion with other operations to create even more intricate designs. Happy modeling!



