Simple Hollow Grids
Hollow grids represent one of the most practical applications of multiple hole creation techniques. These perforated patterns are essential in countless real-world applications - from ventilation panels and acoustic screens to decorative architectural elements and industrial filtration systems.
Creating parametric hollow grids allows you to quickly generate complex perforated patterns that can be easily adjusted for different requirements. Whether you need more holes for better airflow, larger holes for specific filtration needs, or custom spacing for aesthetic purposes, understanding grid-based hole creation opens up tremendous design flexibility.
Creating a Parametric Hollow Grid
The key to creating effective hollow grids lies in understanding how to generate regular patterns of holes programmatically. Instead of manually placing each hole, we use mathematical functions to create systematic arrays of positions, then populate those positions with identical hole shapes.
This approach not only saves time but also ensures perfect regularity and makes it easy to modify the entire grid by changing just a few parameters. The technique scales efficiently from simple 3x3 grids to complex patterns with hundreds of holes.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"4b29b03378383afa": {
"id": "4b29b03378383afa",
"name": "bitbybit.occt.shapes.wire.createCircleWire",
"customName": "circle wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.8,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
508.4205773750531,
128.0777379671664
]
},
"2f3a1f33475f776f": {
"id": "2f3a1f33475f776f",
"name": "bitbybit.vector.span",
"customName": "span",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 2,
"min": -10,
"max": 10
},
"inputs": {
"min": {
"connections": [
{
"node": "d515c5de4782becc",
"output": "result",
"data": {}
}
]
},
"max": {
"connections": [
{
"node": "10e30ee40f79b0ae",
"output": "result",
"data": {}
}
]
}
},
"position": [
506.232234954834,
570.2769775390625
]
},
"2823a45a24b2c78e": {
"id": "2823a45a24b2c78e",
"name": "bitbybit.vector.span",
"customName": "span",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 2,
"min": -10,
"max": 10
},
"inputs": {
"min": {
"connections": [
{
"node": "d515c5de4782becc",
"output": "result",
"data": {}
}
]
},
"max": {
"connections": [
{
"node": "10e30ee40f79b0ae",
"output": "result",
"data": {}
}
]
}
},
"position": [
510.88981013976456,
941.1754150390625
]
},
"eeba6fde2dddcd4b": {
"id": "eeba6fde2dddcd4b",
"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": "8376a1838fd3a8ff",
"output": "result",
"data": {}
}
]
},
"z": {
"connections": [
{
"node": "7421489c641c87bf",
"output": "result",
"data": {}
}
]
}
},
"position": [
1367.4460929204372,
748.9437379500662
]
},
"8376a1838fd3a8ff": {
"id": "8376a1838fd3a8ff",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "2f3a1f33475f776f",
"output": "result",
"data": {}
}
]
}
},
"position": [
886.7919918118296,
606.8678369326631
]
},
"7421489c641c87bf": {
"id": "7421489c641c87bf",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "2823a45a24b2c78e",
"output": "result",
"data": {}
}
]
}
},
"position": [
889.9942177036453,
980.1436873728675
]
},
"a4bdf3794a8ee616": {
"id": "a4bdf3794a8ee616",
"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": "eeba6fde2dddcd4b",
"output": "result",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "4b29b03378383afa",
"output": "result",
"data": {}
}
]
}
},
"position": [
1859.178437356446,
447.99601054907833
]
},
"04abede3b58aacd6": {
"id": "04abede3b58aacd6",
"name": "bitbybit.occt.shapes.wire.createSquareWire",
"customName": "square wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"size": 1,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"size": {
"connections": [
{
"node": "53d2c3623e2cc333",
"output": "result",
"data": {}
}
]
}
},
"position": [
499.19399512863697,
-268.5313972451714
]
},
"cee31da5c8337b91": {
"id": "cee31da5c8337b91",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 10,
"max": 20,
"step": 2,
"width": 350,
"updateOnDrag": false
},
"number": 14
},
"inputs": {},
"position": [
-1333.2955042169851,
522.2420083139696
]
},
"10e30ee40f79b0ae": {
"id": "10e30ee40f79b0ae",
"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": "cee31da5c8337b91",
"output": "result",
"data": {}
}
]
}
},
"position": [
-752.137097650796,
650.0851220211472
]
},
"d515c5de4782becc": {
"id": "d515c5de4782becc",
"name": "bitbybit.math.negate",
"customName": "negate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 1
},
"inputs": {
"number": {
"connections": [
{
"node": "10e30ee40f79b0ae",
"output": "result",
"data": {}
}
]
}
},
"position": [
-311.276400649915,
977.6118653880262
]
},
"53d2c3623e2cc333": {
"id": "53d2c3623e2cc333",
"name": "bitbybit.math.add",
"customName": "add",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 4
},
"inputs": {
"first": {
"connections": [
{
"node": "cee31da5c8337b91",
"output": "result",
"data": {}
}
]
}
},
"position": [
29.246069129951806,
31.313856021349885
]
},
"ffd9246adbc265f0": {
"id": "ffd9246adbc265f0",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "04abede3b58aacd6",
"output": "result",
"data": {}
},
{
"node": "3049919c9e8630e9",
"output": "result",
"data": {}
}
]
}
},
"position": [
3188.1758459648963,
-235.62296468351784
]
},
"3049919c9e8630e9": {
"id": "3049919c9e8630e9",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "fa79f1c960c5a1b7",
"output": "result",
"data": {}
}
]
}
},
"position": [
2640.6065935833612,
488.4733267556971
]
},
"0660179313a0c37d": {
"id": "0660179313a0c37d",
"name": "bitbybit.occt.shapes.face.createFaceFromWires",
"customName": "face from wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"planar": true
},
"inputs": {
"shapes": {
"connections": [
{
"node": "ffd9246adbc265f0",
"output": "list",
"data": {}
}
]
}
},
"position": [
3795.4692022382096,
-276.3540693508603
]
},
"fa79f1c960c5a1b7": {
"id": "fa79f1c960c5a1b7",
"name": "bitbybit.occt.shapes.wire.reversedWire",
"customName": "reversed wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "a4bdf3794a8ee616",
"output": "result",
"data": {}
}
]
}
},
"position": [
2247.1179664764545,
448.1771670504505
]
},
"d3f1c42c891fafc3": {
"id": "d3f1c42c891fafc3",
"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": "0660179313a0c37d",
"output": "result",
"data": {}
}
]
},
"direction": {
"connections": [
{
"node": "c1928e3c1e0c9053",
"output": "result",
"data": {}
}
]
}
},
"position": [
4218.7991259121745,
-278.00706647939234
]
},
"c1928e3c1e0c9053": {
"id": "c1928e3c1e0c9053",
"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.5,
"z": 0
},
"inputs": {},
"position": [
3791.181424976882,
45.51476785730863
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="6F`Np~ypbUBNlh@A]Pc-">gridSize</variable><variable id=")kRAQ;E}Z$({Oj)yYrHa">holeRadius</variable><variable id="pkQd|q.9+UG=fne#yFRB">holeSpacing</variable><variable id="JeFUbK(d5G2~~O^e^uuf">extrudeHeight</variable><variable id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</variable><variable id="%hUZTd{3LoA$*O.~dmH$">boundarySize</variable><variable id="p@ScEkK_$pWJ|N}dJa{I">square</variable><variable id=":w7z|:/z^8|p.YjaQ:7p">xPositions</variable><variable id="fZ2PI*~sO^1-{Myd[f1$">yPositions</variable><variable id="G*;ZvM(M9Fk~bwE2{~tj">wires</variable><variable id="ATM3t~Q6Z*5)3|`.7x3I">x</variable><variable id="H|aSnxVA5?b_gK{Bnc6=">z</variable><variable id="!gV?#E/M;)lO_*zVSz{J">hollowFace</variable><variable id="AXgdZ/Ns#N~#Ice@804,">hollowGridSolid</variable></variables><block type="variables_set" id="%Dt#[h}*ZESujNIxMXVp" x="-173" y="-152"><field name="VAR" id="6F`Np~ypbUBNlh@A]Pc-">gridSize</field><value name="VALUE"><block type="math_number" id="43lgpUPhO[rTR5[Z[[|g"><field name="NUM">14</field></block></value><next><block type="variables_set" id="7A_9qe4fPDs_Lktms~r!"><field name="VAR" id=")kRAQ;E}Z$({Oj)yYrHa">holeRadius</field><value name="VALUE"><block type="math_number" id="tL~`;[yL-([3X=}07PAe"><field name="NUM">0.8</field></block></value><next><block type="variables_set" id="uDm,+q|,*9u1BH/v~FZ("><field name="VAR" id="pkQd|q.9+UG=fne#yFRB">holeSpacing</field><value name="VALUE"><block type="math_number" id="^Ng(/V*W,HM@Lyu}f5}8"><field name="NUM">2</field></block></value><next><block type="variables_set" id="Du)l-1+D+:O9di4p}c+{"><field name="VAR" id="JeFUbK(d5G2~~O^e^uuf">extrudeHeight</field><value name="VALUE"><block type="math_number" id="V*}ld#V^0fp;kZ7O[2z("><field name="NUM">0.5</field></block></value><next><block type="variables_set" id="yu.X;`~5VOh5te.QtW(g"><field name="VAR" id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</field><value name="VALUE"><block type="math_arithmetic" id="qqJ9kLo[e8tHGk~)I$8l"><field name="OP">DIVIDE</field><value name="A"><block type="variables_get" id="u)HH3d@T^bU^,P9+fZ@V"><field name="VAR" id="6F`Np~ypbUBNlh@A]Pc-">gridSize</field></block></value><value name="B"><block type="math_number" id="ul6m|,`NqKjupq-PyP{{"><field name="NUM">2</field></block></value></block></value><next><block type="variables_set" id="S]BPYK{okH/Mf|gZ%8vN"><field name="VAR" id="%hUZTd{3LoA$*O.~dmH$">boundarySize</field><value name="VALUE"><block type="math_arithmetic" id="3c}!freamJYb49;5i06A"><field name="OP">ADD</field><value name="A"><block type="variables_get" id="IX=MvrgJhyJL%)*De~KY"><field name="VAR" id="6F`Np~ypbUBNlh@A]Pc-">gridSize</field></block></value><value name="B"><block type="math_number" id="u,!pV3ny!gnEf3gH8+c5"><field name="NUM">4</field></block></value></block></value><next><block type="variables_set" id="X2*q?Bea~T*Af=;Kzd#X"><field name="VAR" id="p@ScEkK_$pWJ|N}dJa{I">square</field><value name="VALUE"><block type="bitbybit.occt.shapes.wire.createSquareWire" id="%OXpY/pbhV+KVY.fQ:o?"><value name="Size"><block type="variables_get" id=")yel18{SMXj+Sw#G.0(x"><field name="VAR" id="%hUZTd{3LoA$*O.~dmH$">boundarySize</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ" id="iW}Oo`kIsXWTTr0v$L(v"><value name="X"><block type="math_number" id="8;!d|bh%Jg:t-eTAHOzf"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id=".ht^$:%!dNJb%8-Ko2Ll"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="4qglp7RE-bPIku-t(Rzs"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="X|)svsEJ6[$?.T#5RaMr"><value name="X"><block type="math_number" id="c|YCK@LcT-0:wQrk1MrL"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="jZT1E):pM4KAJrw?rk|Q"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="]igGR:nUoNJm1@O)9[)3"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="2d/|s$90/Q-IFlIaVmIh"><field name="VAR" id=":w7z|:/z^8|p.YjaQ:7p">xPositions</field><value name="VALUE"><block type="bitbybit.vector.span" id="ZzWofT[(7PbUxD,^XOPw"><value name="Step"><block type="variables_get" id="J@EUV7!aD+K,(NOPZWB7"><field name="VAR" id="pkQd|q.9+UG=fne#yFRB">holeSpacing</field></block></value><value name="Min"><block type="math_single" id=";j@Z)$$sf_fXMq6vZp|W"><field name="OP">NEG</field><value name="NUM"><block type="variables_get" id="^bbfX8;Dh)$S9L$`s6Xh"><field name="VAR" id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</field></block></value></block></value><value name="Max"><block type="variables_get" id="Rontc8f2~Ubnk%%LZKjR"><field name="VAR" id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</field></block></value></block></value><next><block type="variables_set" id="q(GNExV:xe3TU+iajAw|"><field name="VAR" id="fZ2PI*~sO^1-{Myd[f1$">yPositions</field><value name="VALUE"><block type="bitbybit.vector.span" id="Y_*Oy`*9.~O%1C5L{s;H"><value name="Step"><block type="variables_get" id="*W1a?2q:0Bvl5,!R$/If"><field name="VAR" id="pkQd|q.9+UG=fne#yFRB">holeSpacing</field></block></value><value name="Min"><block type="math_single" id="FgY~B@U1B`a^Lv@T%+f)"><field name="OP">NEG</field><value name="NUM"><block type="variables_get" id="OKH0OD9PzX)yPxfqd0fq"><field name="VAR" id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</field></block></value></block></value><value name="Max"><block type="variables_get" id="z9`R@cb=5l.N{-PG|p0o"><field name="VAR" id=";E/]{U*qM)iiz,X*g:Z:">halfGrid</field></block></value></block></value><next><block type="variables_set" id="Y95)f=bBF!$lB:w|nrhC"><field name="VAR" id="G*;ZvM(M9Fk~bwE2{~tj">wires</field><value name="VALUE"><block type="lists_create_with" id="@0l/;%|[6UI4/-rH3*GR"><mutation items="1"></mutation><value name="ADD0"><block type="variables_get" id="e2n%k{AL!.JQb~pYAFm="><field name="VAR" id="p@ScEkK_$pWJ|N}dJa{I">square</field></block></value></block></value><next><block type="controls_for" id="2SFR;af9bS5(qQ7Qs!9@"><field name="VAR" id="ATM3t~Q6Z*5)3|`.7x3I">x</field><value name="FROM"><block type="math_number" id="OzXK~Ph(Zsul7`WWiO)z"><field name="NUM">1</field></block></value><value name="TO"><block type="lists_length" id="dDjf;-zocOXnF6oh.=,/"><value name="VALUE"><block type="variables_get" id="T]0!^3vlnB;sKn2AUrC~"><field name="VAR" id=":w7z|:/z^8|p.YjaQ:7p">xPositions</field></block></value></block></value><value name="BY"><block type="math_number" id="9=zk=nJxZh)+?^xdK|I3"><field name="NUM">1</field></block></value><statement name="DO"><block type="controls_for" id="Ba^n.mFQ0Oa(E-4]gqHM"><field name="VAR" id="H|aSnxVA5?b_gK{Bnc6=">z</field><value name="FROM"><block type="math_number" id=";vyN~7*i3ckDJju`N?y^"><field name="NUM">1</field></block></value><value name="TO"><block type="lists_length" id="X?G_{n5daDr+KF?T@#qR"><value name="VALUE"><block type="variables_get" id="jsI51m-zy]sCnAj)O3B/"><field name="VAR" id=":w7z|:/z^8|p.YjaQ:7p">xPositions</field></block></value></block></value><value name="BY"><block type="math_number" id="Cyb?Xr[??U.NoXj5)kMu"><field name="NUM">1</field></block></value><statement name="DO"><block type="lists_setIndex" id="iT$v-8xn@y5d)+UkIZb7"><mutation at="false"></mutation><field name="MODE">INSERT</field><field name="WHERE">LAST</field><value name="LIST"><block type="variables_get" id="i!QpNorOd__/vYx9ws^:"><field name="VAR" id="G*;ZvM(M9Fk~bwE2{~tj">wires</field></block></value><value name="TO"><block type="bitbybit.occt.shapes.wire.reversedWire" id="jgd.WR.i[/nAE{:aMdnz"><value name="Shape"><block type="bitbybit.occt.shapes.wire.createCircleWire" id="(CUg8O@S%GHfRC,h;Di}"><value name="Radius"><block type="variables_get" id="pEMXGKi}:BV/R/R|D8Z-"><field name="VAR" id=")kRAQ;E}Z$({Oj)yYrHa">holeRadius</field></block></value><value name="Center"><block type="lists_create_with" id="kl!|;/q4=R}pA^_d7pgh"><mutation items="3"></mutation><value name="ADD0"><block type="lists_getIndex" id="#Ve27I~#xjSV_X`Fa-2Y"><mutation statement="false" at="true"></mutation><field name="MODE">GET</field><field name="WHERE">FROM_START</field><value name="VALUE"><block type="variables_get" id="ITsR`Q(y.NzR6y!g^-X8"><field name="VAR" id=":w7z|:/z^8|p.YjaQ:7p">xPositions</field></block></value><value name="AT"><block type="variables_get" id="VMCcs/h~5uS4j]H$ZhF["><field name="VAR" id="ATM3t~Q6Z*5)3|`.7x3I">x</field></block></value></block></value><value name="ADD1"><block type="math_number" id="N@iqd3*bSbmEl*,o^SR@"><field name="NUM">0</field></block></value><value name="ADD2"><block type="lists_getIndex" id="a|:KC(G3!lqZgI4[D4x^"><mutation statement="false" at="true"></mutation><field name="MODE">GET</field><field name="WHERE">FROM_START</field><value name="VALUE"><block type="variables_get" id="~j$Z09Igb{D3jiZKi!6+"><field name="VAR" id="fZ2PI*~sO^1-{Myd[f1$">yPositions</field></block></value><value name="AT"><block type="variables_get" id="LSoI4GMzpAMOiuI:NUw?"><field name="VAR" id="H|aSnxVA5?b_gK{Bnc6=">z</field></block></value></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="GkyW3DVl-F77odPKoaBy"><value name="X"><block type="math_number" id="Jjch(npme{{2/$YE:OMF"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="FtS1yl0AFn`]k3h1t%)F"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="v/T,t_?cGfrr5RED9HoY"><field name="NUM">0</field></block></value></block></value></block></value></block></value></block></statement></block></statement><next><block type="variables_set" id="B9:WYyZzUPx[#GcYglhr"><field name="VAR" id="!gV?#E/M;)lO_*zVSz{J">hollowFace</field><value name="VALUE"><block type="bitbybit.occt.shapes.face.createFaceFromWires" id="xYPi;$Jrr!cExM#Si{*#"><value name="Shapes"><block type="variables_get" id="6kBz!lj+]7N;C%sIHo1V"><field name="VAR" id="G*;ZvM(M9Fk~bwE2{~tj">wires</field></block></value><value name="Planar"><block type="logic_boolean" id="gWZDxUfpMpgl{z;$P;3t"><field name="BOOL">TRUE</field></block></value></block></value><next><block type="variables_set" id=".8PK^S=!fRx{;x-WEgt/"><field name="VAR" id="AXgdZ/Ns#N~#Ice@804,">hollowGridSolid</field><value name="VALUE"><block type="bitbybit.occt.operations.extrude" id="c,b[HG%zR/5_hHW2+s[N"><value name="Shape"><block type="variables_get" id=":;=wRE#%n1]/fy?e]tSq"><field name="VAR" id="!gV?#E/M;)lO_*zVSz{J">hollowFace</field></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="H{LAh+W|@DGp70M?7/c,"><value name="X"><block type="math_number" id="p9QU:zZ[/C;My^_:7)uV"><field name="NUM">0</field></block></value><value name="Y"><block type="variables_get" id="/Sx:S^aGHvur4$g(q7vh"><field name="VAR" id="JeFUbK(d5G2~~O^e^uuf">extrudeHeight</field></block></value><value name="Z"><block type="math_number" id="rO/_Y[Y8n$S)DL@pFe]R"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="{z{5*6Jp2)@B2TEfL/O^"><value name="Entity"><block type="variables_get" id="e#fu)T7xUL8r!|83-TF3"><field name="VAR" id="AXgdZ/Ns#N~#Ice@804,">hollowGridSolid</field></block></value></block></next></block></next></block></next></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 grids, shapes, and operations
const { SquareDto, CircleDto, FaceFromWiresDto, ExtrudeDto } = Bit.Inputs.OCCT;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
// Get access to OCCT modules and utility functions
const { wire, face } = bitbybit.occt.shapes;
const { operations, transforms } = bitbybit.occt;
const { vector } = bitbybit;
// Define the main function to create a parametric hollow grid
const start = async () => {
// Grid parameters - easily adjustable for different requirements
const gridSize = 14; // Overall grid dimension
const holeRadius = 0.8; // Radius of each circular hole
const holeSpacing = 2; // Distance between hole centers
const extrudeHeight = 0.5; // Thickness of the final solid
// Calculate grid boundaries
const halfGrid = gridSize / 2;
const boundarySize = gridSize + 4; // Add padding around holes
// Create the outer boundary wire (square frame)
const boundaryOptions = new SquareDto();
boundaryOptions.size = boundarySize;
boundaryOptions.center = [0, 0, 0];
boundaryOptions.direction = [0, 1, 0];
const boundaryWire = await wire.createSquareWire(boundaryOptions);
// Generate grid positions using span functions
const xPositions = vector.span({
min: -halfGrid,
max: halfGrid,
step: holeSpacing
});
const zPositions = vector.span({
min: -halfGrid,
max: halfGrid,
step: holeSpacing
});
// Create grid points by combining X and Z coordinates
const gridPoints: Point3[] = [];
for (const xPos of xPositions) {
for (const zPos of zPositions) {
gridPoints.push([xPos, 0, zPos]);
}
}
// Create the hole template (circular wire)
const holeOptions = new CircleDto();
holeOptions.radius = holeRadius;
holeOptions.center = [0, 0, 0];
holeOptions.direction = [0, 1, 0];
const holeTemplate = await wire.createCircleWire(holeOptions);
// Create holes at each grid position
const holes: TopoDSWirePointer[] = [];
for (const position of gridPoints) {
const translatedHole = await transforms.translate({
shape: holeTemplate,
translation: position
});
// Reverse each hole wire for proper orientation
const reversedHole = await wire.reversedWire({ shape: translatedHole });
holes.push(reversedHole);
}
// Combine boundary and all holes into a single wire list
const allWires = [boundaryWire, ...holes];
// Create a face from the boundary and all holes
const faceOptions = new FaceFromWiresDto<TopoDSWirePointer>();
faceOptions.shapes = allWires;
faceOptions.planar = true;
const gridFace = await face.createFaceFromWires(faceOptions);
// Extrude the face to create a 3D hollow grid
const extrudeOptions = new ExtrudeDto<TopoDSFacePointer>();
extrudeOptions.shape = gridFace;
extrudeOptions.direction = [0, extrudeHeight, 0];
const hollowGrid = await operations.extrude(extrudeOptions);
// Draw the resulting hollow grid
bitbybit.draw.drawAnyAsync({
entity: hollowGrid
});
}
// Execute the function
start();
Understanding Grid Generation Logic
The power of parametric grid creation lies in understanding how to systematically generate positions. The example above demonstrates several key concepts:
Span Functions: These create evenly spaced arrays of numbers that define our grid coordinates. By using vector.span() with minimum, maximum, and step values, we can quickly generate regular spacing patterns.
Coordinate Combination: Grid positions are created by combining X and Z coordinates while keeping Y constant (since we're working in a horizontal plane). This creates a Cartesian product of positions.
Template Replication: Instead of creating each hole individually, we create one template hole and translate copies to each grid position. This ensures perfect consistency and reduces computational overhead.
Wire Orientation: Each hole is reversed to ensure proper orientation when combined with the outer boundary. This maintains the hollow structure throughout the grid.
Applications and Design Considerations
The parametric approach demonstrated here makes hollow grids incredibly versatile. You can easily customize hole shapes from circles to squares or hexagons, adjust grid patterns for rectangular layouts, or modify boundary shapes to fit specific requirements.
These techniques are particularly valuable in HVAC systems where precise airflow patterns are critical, architectural projects requiring decorative perforated screens, and industrial applications like filtration systems or acoustic panels. The ability to quickly adjust parameters means you can optimize designs for different performance requirements while maintaining consistency.
When implementing these patterns in real projects, consider the balance between open area and structural strength, manufacturing constraints of your chosen production method, and how the perforation pattern affects the functional performance of your design. The parametric foundation provided here scales effectively from simple prototypes to complex industrial applications.



