Creating Advanded Loft
The file explains how to create complex 3D shapes using an advanced lofting operation. This operation generates a surface or solid by connecting a series of 2D wire profiles, offering more control than a simple loft.
Here's a breakdown of the process described:
- Profile Creation: The script begins by creating three distinct n-sided polygonal wires (using
createNGonWire). These wires serve as the cross-sections for the loft. Each wire can be customized with a different number of corners, radius, and spatial position. - Profile Refinement: To achieve smoother transitions, 2D fillets (using
fillet2d) are applied to the corners of these polygonal wires. - Advanced Loft Operation: The core of the script is the
loftAdvancedfunction. This function takes the refined wire profiles and a set of parameters to generate the final 3D shape.
Key Parameters for loftAdvanced
shapes: This is the list of 2D wire profiles that the loft will pass through.startVertexandendVertex: These optional parameters allow the loft to begin or end at a single point, creating a tapered or pointed shape.makeSolid: A boolean that determines whether the output is a hollow shell (surface) or a solid object.closed: If set to true, the loft connects the last profile back to the first, forming a closed loop.periodic: Useful for creating smooth, continuous surfaces when the input profiles form a repeating pattern.straight: When true, the loft creates ruled surfaces, meaning it uses straight lines to connect corresponding points on adjacent profiles.useSmoothing: Applies a smoothing algorithm to the generated surface for a more organic look.maxUDegree: Controls the maximum degree of the resulting BSpline surface in the U direction.tolerance: Defines the geometric precision for the lofting operation.parType: Specifies the method used for parameterizing the surface along the path of the loft (e.g.,approxCentripetal,approxChordLength).
Overlap with Simple Loft
- Fundamental Principle: Both simple and advanced lofting share the core concept of creating a 3D form by sweeping through a sequence of 2D profiles. The basic input of a list of shapes (wires) is common to both.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"5b0a2e7a36e52bc6": {
"id": "5b0a2e7a36e52bc6",
"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": {},
"position": [
-294.44305408107294,
625.494016393214
]
},
"31cc8830d0d5b8d6": {
"id": "31cc8830d0d5b8d6",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 7,
"z": 0
},
"inputs": {},
"position": [
-297.9642807136139,
1019.3121779042008
]
},
"8bd8f5d69c0ee3d9": {
"id": "8bd8f5d69c0ee3d9",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "11be4dd28dcd4b33",
"output": "result",
"data": {}
},
{
"node": "3522cf5d866d7d91",
"output": "result",
"data": {}
},
{
"node": "d469db5335ea3400",
"output": "result",
"data": {}
}
]
}
},
"position": [
1276.7110950696322,
648.5670623793434
]
},
"71104a241cda7a83": {
"id": "71104a241cda7a83",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"options": {
"connections": [
{
"node": "2b01c4bcdaa8b222",
"output": "result",
"data": {}
}
]
},
"entity": {
"connections": [
{
"node": "e589c6b135aa1393",
"output": "result",
"data": {}
}
]
}
},
"position": [
2216.0217964086746,
945.9977380414867
]
},
"2b01c4bcdaa8b222": {
"id": "2b01c4bcdaa8b222",
"name": "bitbybit.draw.optionsOcctShapeSimple",
"customName": "options occt shape simple",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"precision": 0.008,
"drawFaces": true,
"faceColour": "#8000ff",
"drawEdges": true,
"edgeColour": "#ffffff",
"edgeWidth": 2
},
"inputs": {},
"position": [
1690.6871109875997,
1317.9796252756155
]
},
"e589c6b135aa1393": {
"id": "e589c6b135aa1393",
"name": "bitbybit.occt.operations.loftAdvanced",
"customName": "loft advanced",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"makeSolid": false,
"closed": false,
"periodic": false,
"straight": false,
"nrPeriodicSections": 10,
"useSmoothing": false,
"maxUDegree": 3,
"tolerance": 1e-7,
"parType": "approxCentripetal"
},
"inputs": {
"shapes": {
"connections": [
{
"node": "8bd8f5d69c0ee3d9",
"output": "list",
"data": {}
}
]
},
"startVertex": {
"connections": [
{
"node": "e00b530f027cb3cf",
"output": "result",
"data": {}
}
]
},
"endVertex": {
"connections": [
{
"node": "8dd22a99e9b89b2c",
"output": "result",
"data": {}
}
]
}
},
"position": [
1682.426755659047,
607.1297407593821
]
},
"8743a42520c8d1c3": {
"id": "8743a42520c8d1c3",
"name": "bitbybit.occt.shapes.wire.createNGonWire",
"customName": "ngon wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"nrCorners": 6,
"radius": 3
},
"inputs": {
"nrCorners": {
"connections": [
{
"node": "64f3dc2622aaf590",
"output": "result",
"data": {}
}
]
}
},
"position": [
442.8040971986445,
241.22876028466678
]
},
"ac432e5d7a5200e3": {
"id": "ac432e5d7a5200e3",
"name": "bitbybit.occt.shapes.wire.createNGonWire",
"customName": "ngon wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"nrCorners": 6,
"radius": 1
},
"inputs": {
"center": {
"connections": [
{
"node": "5b0a2e7a36e52bc6",
"output": "result",
"data": {}
}
]
},
"nrCorners": {
"connections": [
{
"node": "64f3dc2622aaf590",
"output": "result",
"data": {}
}
]
}
},
"position": [
442.3146113374279,
621.9002839093048
]
},
"c5e492a02fd8859d": {
"id": "c5e492a02fd8859d",
"name": "bitbybit.occt.shapes.wire.createNGonWire",
"customName": "ngon wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"nrCorners": 6,
"radius": 6
},
"inputs": {
"center": {
"connections": [
{
"node": "31cc8830d0d5b8d6",
"output": "result",
"data": {}
}
]
},
"nrCorners": {
"connections": [
{
"node": "64f3dc2622aaf590",
"output": "result",
"data": {}
}
]
}
},
"position": [
443.91583594610427,
1006.2290060921524
]
},
"3522cf5d866d7d91": {
"id": "3522cf5d866d7d91",
"name": "bitbybit.occt.fillets.fillet2d",
"customName": "fillet 2d",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.3
},
"inputs": {
"shape": {
"connections": [
{
"node": "ac432e5d7a5200e3",
"output": "result",
"data": {}
}
]
}
},
"position": [
853.6233508415709,
620.7419018219557
]
},
"64f3dc2622aaf590": {
"id": "64f3dc2622aaf590",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 3,
"max": 10,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 10
},
"inputs": {},
"position": [
-541.8367158412975,
362.3552015537263
]
},
"d469db5335ea3400": {
"id": "d469db5335ea3400",
"name": "bitbybit.occt.fillets.fillet2d",
"customName": "fillet 2d",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 1
},
"inputs": {
"shape": {
"connections": [
{
"node": "8743a42520c8d1c3",
"output": "result",
"data": {}
}
]
}
},
"position": [
851.3977807392785,
238.02015166684114
]
},
"11be4dd28dcd4b33": {
"id": "11be4dd28dcd4b33",
"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": "c5e492a02fd8859d",
"output": "result",
"data": {}
}
]
}
},
"position": [
852.7507275204114,
1002.0571428632672
]
},
"e00b530f027cb3cf": {
"id": "e00b530f027cb3cf",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 10,
"z": 0
},
"inputs": {},
"position": [
1281.5387853734014,
883.3651422481488
]
},
"8dd22a99e9b89b2c": {
"id": "8dd22a99e9b89b2c",
"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": {},
"position": [
1281.0131144912798,
1233.3391294416137
]
},
"9419c83e5db4e3ec": {
"id": "9419c83e5db4e3ec",
"name": "bitbybit.babylon.scene.adjustActiveArcRotateCamera",
"customName": "adjust active arc rotate camera",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"position": [
10,
10,
10
],
"lookAt": [
0,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {
"lookAt": {
"connections": [
{
"node": "60cc6a6554a486c3",
"output": "result",
"data": {}
}
]
},
"position": {
"connections": [
{
"node": "2610f0aa01da8491",
"output": "result",
"data": {}
}
]
}
},
"position": [
446.1321692664079,
1396.818212894413
]
},
"60cc6a6554a486c3": {
"id": "60cc6a6554a486c3",
"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": {},
"position": [
-302.7615363793083,
1739.5547926387696
]
},
"2610f0aa01da8491": {
"id": "2610f0aa01da8491",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 15,
"y": 15,
"z": 15
},
"inputs": {},
"position": [
-302.43034583359827,
1401.0514769387867
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="/zg8,D_FA*vR}[cBcgW/">nrCorners</variable><variable id="JZ((:rO6/O@vdWNctJER">wire1</variable><variable id="rGzY+7?vH.:{Mb~MNA,x">wire2</variable><variable id=",DPb!`UqN3!D?48Th0xL">wire3</variable></variables><block type="variables_set" id="piOe?bod_s)|a_@S+ai," x="-159" y="-660"><field name="VAR" id="/zg8,D_FA*vR}[cBcgW/">nrCorners</field><value name="VALUE"><block type="math_number" id="2Q6u8e#sRHwziW?nRcUj"><field name="NUM">10</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera" id="6+tV-byjMBXS-#z_4:}$"><value name="Position"><block type="bitbybit.point.pointXYZ" id=".`OdoY!24Dk.|wcr5}hP"><value name="X"><block type="math_number" id="~,J;t-Dyd.O~7k#ej2uS"><field name="NUM">15</field></block></value><value name="Y"><block type="math_number" id="feV(B*0N2$Gz1WYQ!YIh"><field name="NUM">15</field></block></value><value name="Z"><block type="math_number" id="T+!8G.kbl%jmd8f*-mRo"><field name="NUM">15</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ" id="sN:gG`_IBIF]P)pJIuJX"><value name="X"><block type="math_number" id="JBK1xq[HbuCR)JyEU9Ky"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="k;D]X%?hE8z3*[-*Fhk9"><field name="NUM">3</field></block></value><value name="Z"><block type="math_number" id="q[W03`j,(9hq/Wm?@s^o"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number" id="Te`o9eH$`.Q:aQhr7+xN"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number" id="~~WX[k,MWa|1hJ]Qv^)Y"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number" id="7|xG%lBRxD(@,r8yU.dl"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number" id="2)3[I3ny`Q}FB%Xj!AuW"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number" id="@VAWYdt3|%!mPV_L}?`X"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number" id="w7|],li%SOc8[Rx2,d*V"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number" id=":~wM}(Z4u_YvOof,BRT/"><field name="NUM">3</field></block></value><next><block type="variables_set" id=")PTsn]7I#0~G@^FZoBUD"><field name="VAR" id="JZ((:rO6/O@vdWNctJER">wire1</field><value name="VALUE"><block type="bitbybit.occt.fillets.fillet2d" id="g.pVTy:o{KHs;dnBZEK+"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createNGonWire" id="}Wq;3dWp($;~h2gi9V7j"><value name="Center"><block type="bitbybit.point.pointXYZ" id="eNMadH@?.O/+%BxHp.kw"><value name="X"><block type="math_number" id="U}Amrp_JNn~5JzKg{Qx:"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="E,?i;YD;Olo.k=_#94iC"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="5AKo;,H{3!{Zr8t=@CRx"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="V)%I8X:/K@U7vNzxHWq0"><value name="X"><block type="math_number" id="3sDEpQQhm9{SaX/nhUZ9"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="}V((hWhY.=m(.k(_qwip"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="(.8Zz7mwBqKJS|G@Z8IL"><field name="NUM">0</field></block></value></block></value><value name="NrCorners"><block type="variables_get" id="]R|h5k{mi8Y-2L[^q)%O"><field name="VAR" id="/zg8,D_FA*vR}[cBcgW/">nrCorners</field></block></value><value name="Radius"><block type="math_number" id="Ue]#yK8Z~H.F.94qfv%g"><field name="NUM">3</field></block></value></block></value><value name="Radius"><block type="math_number" id="Y6ly6hI7Bu+e2hL_UT^h"><field name="NUM">1</field></block></value></block></value><next><block type="variables_set" id="w(lP~`Rvj^ZAsw5TK9Ww"><field name="VAR" id="rGzY+7?vH.:{Mb~MNA,x">wire2</field><value name="VALUE"><block type="bitbybit.occt.fillets.fillet2d" id="ZY@$Vo.A|Z+f_0w-@x+|"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createNGonWire" id="pLUO6I2%wynp~$2MKuz}"><value name="Center"><block type="bitbybit.point.pointXYZ" id="%_R%f.?Ay76L8;syhN^W"><value name="X"><block type="math_number" id="5/l0kr659W3uyMVj(*cc"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="1N0!@h0cT{6.N${Lqvr!"><field name="NUM">3</field></block></value><value name="Z"><block type="math_number" id="G/Z~W,zL-1m[:0N*/R,j"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="e9ch9tx]pRD?z+T$ghLy"><value name="X"><block type="math_number" id="@Py-c1/mbo+e]4{lZU-+"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="c~wr-)TfPLw/-IMhcS}-"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="su?Nz06#(;O-LJvvMhAl"><field name="NUM">0</field></block></value></block></value><value name="NrCorners"><block type="variables_get" id="L`q|roFLi%ycKN,}+FHD"><field name="VAR" id="/zg8,D_FA*vR}[cBcgW/">nrCorners</field></block></value><value name="Radius"><block type="math_number" id="Ags(i.*W?%3$5]s0%(;$"><field name="NUM">1</field></block></value></block></value><value name="Radius"><block type="math_number" id="j1QrN{dS9gb{3gdoxxkO"><field name="NUM">0.3</field></block></value></block></value><next><block type="variables_set" id="l1`Bo/VDhv=,rVEQ*pu_"><field name="VAR" id=",DPb!`UqN3!D?48Th0xL">wire3</field><value name="VALUE"><block type="bitbybit.occt.fillets.fillet2d" id="#bfp15x-F(84J~zRcMdx"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createNGonWire" id="L)u9[;eA4A-pb:/;PSp4"><value name="Center"><block type="bitbybit.point.pointXYZ" id="~(:sqgeI6jHGzsrG3ZxS"><value name="X"><block type="math_number" id="[PdbC)!:D/y?n*kJ0ZCL"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="|{7qE9G.`{l9$_}}qaxy"><field name="NUM">7</field></block></value><value name="Z"><block type="math_number" id="JY@^RZA~fl^OKzsyz|N3"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="xd:s[yY6n`ud;{a*#4,["><value name="X"><block type="math_number" id="wB@+Zeh0-+xsxA0)!CM^"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="t=1eCU0nTvG8blcPWE^_"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="$B/07[E^wrPGyQecmt7N"><field name="NUM">0</field></block></value></block></value><value name="NrCorners"><block type="variables_get" id="C_QviGD.r*1x=9:i+HT4"><field name="VAR" id="/zg8,D_FA*vR}[cBcgW/">nrCorners</field></block></value><value name="Radius"><block type="math_number" id="]1e`GY~oWV[Nfb(7F[%t"><field name="NUM">6</field></block></value></block></value><value name="Radius"><block type="math_number" id="fv%5#y9CHRnAWy~uyC$~"><field name="NUM">0.5</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id=")uBG-jwTCL+g|{]aSaxT"><value name="Entity"><block type="bitbybit.occt.operations.loftAdvanced" id="9lit#kMat[hwXI;@lzqw"><value name="Shapes"><block type="lists_create_with" id="~ovfVMx=${1uCN!2bmWD"><mutation items="3"></mutation><value name="ADD0"><block type="variables_get" id="7g{Le$r7XXf1@w)exxKs"><field name="VAR" id=",DPb!`UqN3!D?48Th0xL">wire3</field></block></value><value name="ADD1"><block type="variables_get" id="*=m:OUQ`RMfj4{h2u2{}"><field name="VAR" id="rGzY+7?vH.:{Mb~MNA,x">wire2</field></block></value><value name="ADD2"><block type="variables_get" id="g~:fJa:9.5_cO2!9X59U"><field name="VAR" id="JZ((:rO6/O@vdWNctJER">wire1</field></block></value></block></value><value name="MakeSolid"><block type="logic_boolean" id="zg4HwD8tFAuvT67O0i7u"><field name="BOOL">FALSE</field></block></value><value name="Closed"><block type="logic_boolean" id="KIwa|:%hL~r;q2deT9I3"><field name="BOOL">FALSE</field></block></value><value name="Periodic"><block type="logic_boolean" id="DP+gD.Ke8ok_0pIO4T5~"><field name="BOOL">FALSE</field></block></value><value name="Straight"><block type="logic_boolean" id="Upxq1C%Fv6}YRrO84X,/"><field name="BOOL">FALSE</field></block></value><value name="NrPeriodicSections"><block type="math_number" id="XZz$[HL:Xuryy{a(GENG"><field name="NUM">10</field></block></value><value name="UseSmoothing"><block type="logic_boolean" id="/SS@.,JW{EQ`.|r_!0,~"><field name="BOOL">FALSE</field></block></value><value name="MaxUDegree"><block type="math_number" id="7IO(q*Ebg{vRIU;{*KGP"><field name="NUM">3</field></block></value><value name="Tolerance"><block type="math_number" id="(ubk[IN94i|G*x7L5c-^"><field name="NUM">1e-7</field></block></value><value name="ParType"><block type="bitbybit.occt.enums.approxParametrizationTypeEnum" id="lG3k_dsR!H[zk[(EnH:M"><field name="bitbybit.occt.enums.approxParametrizationTypeEnum">'approxChordLength'</field></block></value><value name="StartVertex"><block type="bitbybit.point.pointXYZ" id="#P_(Tw;P|(muv14U?jZ{"><value name="X"><block type="math_number" id="Q(`IQiT](/;MX61e{`pH"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="T}u45Dq(-Ste.`7A%IqN"><field name="NUM">10</field></block></value><value name="Z"><block type="math_number" id="se?m39ts*VL9GhEG[utI"><field name="NUM">0</field></block></value></block></value><value name="EndVertex"><block type="bitbybit.point.pointXYZ" id="=N|F.o?LJNK4.ptpC?eS"><value name="X"><block type="math_number" id="tj6@e?fk/-izXAsbH`WD"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="!IR!AiQBppdEj#2S;aY;"><field name="NUM">-3</field></block></value><value name="Z"><block type="math_number" id="3rJ~c6-`y$v:.8C9KG69"><field name="NUM">0</field></block></value></block></value></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeSimple" id=":]@sAcs$+4,-pL/6ybQ}"><value name="Precision"><block type="math_number" id=":cIkpc@6oyrPnD@Iyvld"><field name="NUM">0.01</field></block></value><value name="DrawFaces"><block type="logic_boolean" id="tps2;z0[=VO@*@^v)*t@"><field name="BOOL">TRUE</field></block></value><value name="FaceColour"><block type="colour_picker" id="WFix-KQ72/hvI|8VG)hn"><field name="COLOUR">#cc33cc</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="mbdm|Iun/K0m2Y70eYP6"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="colour_picker" id="k$c?2KyWi$~CkiD]HK*g"><field name="COLOUR">#ffffff</field></block></value><value name="EdgeWidth"><block type="math_number" id="5w1hI~4|N{e1%3TrIPO9"><field name="NUM">2</field></block></value></block></value></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import DTOs for configuring various operations. DTOs are objects used to pass data.
// Import camera configuration for setting up the scene view.
const { CameraConfigurationDto } = Bit.Inputs.BabylonScene;
// Import DTOs for OpenCASCADE (OCCT) geometric modeling: creating polygons, fillets, and lofts.
const { NGonWireDto, FilletDto, LoftAdvancedDto } = Bit.Inputs.OCCT;
// Import DTO for specifying drawing options, like color and opacity.
const { DrawOcctShapeSimpleOptions } = Bit.Inputs.Draw;
// Import a specific type for an OCCT wire, ensuring type safety in our code.
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
// Destructure the bitbybit API to get direct access to its main modules.
// 'scene' provides access to BabylonJS scene controls.
const { scene } = bitbybit.babylon;
// 'wire', 'fillets', and 'operations' are part of the OCCT module for creating and manipulating shapes.
const { wire } = bitbybit.occt.shapes;
const { fillets, operations } = bitbybit.occt;
// Define an asynchronous function to execute the main logic.
// Using async/await is necessary because geometry creation and drawing are non-blocking operations.
const start = async () => {
// --- 1. Camera Configuration ---
// Create a new configuration object for the scene's Arc Rotate Camera.
const arcCameraOptions = new CameraConfigurationDto();
// Set the camera's position in 3D space (x, y, z).
arcCameraOptions.position = [15, 15, 15];
// Set the point the camera will look at.
arcCameraOptions.lookAt = [0, 3, 0];
// Apply these settings to the active camera in the scene.
scene.adjustActiveArcRotateCamera(arcCameraOptions);
// Define the number of corners for the polygonal profiles.
const nrCorners = 10;
// --- 2. Create the First Profile (Bottom) ---
// Create a DTO to define an n-sided polygon wire.
const ngonOpt = new NGonWireDto();
ngonOpt.nrCorners = nrCorners;
ngonOpt.radius = 3;
// Asynchronously create the first polygon wire shape at the default center [0,0,0].
const wire1 = await wire.createNGonWire(ngonOpt);
// Create a DTO for a 2D fillet operation to round the corners of a wire.
const filletOpt = new FilletDto<TopoDSWirePointer>();
filletOpt.radius = 0.3; // The radius of the rounded corners.
filletOpt.shape = wire1; // Specify that the fillet should be applied to wire1.
// Asynchronously apply the fillet and store the new, smoothed wire.
const filletedWire1 = await fillets.fillet2d(filletOpt);
// --- 3. Create the Second Profile (Middle) ---
// Reuse the ngonOpt DTO but modify its properties for the next shape.
ngonOpt.center = [0, 3, 0]; // Move the center up along the Y-axis.
ngonOpt.radius = 1; // Make this polygon smaller.
const wire2 = await wire.createNGonWire(ngonOpt);
// Reuse the filletOpt DTO to apply the same fillet radius to the new wire.
filletOpt.shape = wire2;
const filletedWire2 = await fillets.fillet2d(filletOpt);
// --- 4. Create the Third Profile (Top) ---
// Reuse and modify the DTOs again for the third and final profile.
ngonOpt.center = [0, 7, 0]; // Move this one even higher.
ngonOpt.radius = 6; // Make this polygon the largest.
const wire3 = await wire.createNGonWire(ngonOpt);
// Use a larger fillet radius for this larger wire.
filletOpt.radius = 0.5;
filletOpt.shape = wire3;
const filletedWire3 = await fillets.fillet2d(filletOpt);
// --- 5. Perform the Loft Operation ---
// A loft creates a 3D solid by connecting a series of 2D profiles.
const loftAdvancedOptions = new LoftAdvancedDto<TopoDSWirePointer>();
// Specify a single point where the loft should begin, creating a pointed top.
loftAdvancedOptions.startVertex = [0, 10, 0];
// Specify a single point where the loft should end, creating a pointed bottom.
loftAdvancedOptions.endVertex = [0, -3, 0];
// Provide the array of profiles to connect. The order matters.
loftAdvancedOptions.shapes = [filletedWire3, filletedWire2, filletedWire1];
// Asynchronously execute the loft operation to create the final 3D shape.
const loftedShape = await operations.loftAdvanced(loftAdvancedOptions)
// --- 6. Draw the Final Shape ---
// Create a DTO to define how the shape should be drawn.
const drawOptions = new DrawOcctShapeSimpleOptions();
// Set the color of the shape's faces to magenta.
drawOptions.faceColour = "#ff00ff";
// Call the generic drawing function to render the OCCT shape in the scene.
bitbybit.draw.drawAnyAsync({
entity: loftedShape, // The shape to draw.
options: drawOptions // The drawing options to apply.
});
}
// Execute the main function to start the script.
start();
Conclusions
The advanced loft operation provides a much richer set of tools for controlling the lofting process compared to a basic loft. While a simple loft typically connects profiles in a straightforward manner, loftAdvanced allows for:
- The creation of either solid bodies or open surfaces (shells).
- The ability to close the loft into a continuous loop or make it periodic.
- The option to taper the loft to a specific start or end point.
- Fine-grained control over the surface's smoothness, straightness (ruled surfaces), and mathematical definition (degree, parameterization).
This makes the advanced loft operation highly versatile for generating complex, precise, and aesthetically refined 3D geometries. The example demonstrates this by creating a shape from three filleted n-gon wires, with the added capability of defining specific start and end vertices for the loft.



