Skip to main content

Freeform surfaces

Planes, cylinders and spheres cover most parts, but a terrain, a canopy or a car body needs a surface with no simple formula behind it. OCCT stores these as B-spline surfaces, and bitbybit.occt.shapes.face can build one from points or from curves.

A surface through points​

fromPointGrid takes rows of points, every row the same length, and fits one smooth face to them. With interpolate on the surface passes through every point; with it off the surface runs near them, within tolerance.

This terrain starts from a survey of 49 points, kept as JSON. The surface is extruded straight down into a solid, the solid is trimmed to a square by booleans.intersection, and operations.slice cuts the hill into flat outlines every 0.5 in height. A level can hold more than one outline where the ground has separate peaks. Each outline is then extruded by 0.42, which leaves a thin gap between the plates, like the glue lines of a model cut from plywood:

Bitbybit Platform

A terrain cut into layers in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"survey": {
"id": "survey",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[[[-10.0,1.0,-10.0],[-10.0,1.05,-6.67],[-10.0,1.27,-3.33],[-10.0,1.7,0.0],[-10.0,1.77,3.33],[-10.0,1.35,6.67],[-10.0,1.07,10.0]],[[-6.67,1.01,-10.0],[-6.67,1.18,-6.67],[-6.67,2.08,-3.33],[-6.67,3.76,0.0],[-6.67,4.01,3.33],[-6.67,2.39,6.67],[-6.67,1.27,10.0]],[[-3.33,1.02,-10.0],[-3.33,1.3,-6.67],[-3.33,2.8,-3.33],[-3.33,5.61,0.0],[-3.33,6.02,3.33],[-3.33,3.32,6.67],[-3.33,1.46,10.0]],[[0.0,1.03,-10.0],[0.0,1.36,-6.67],[0.0,2.48,-3.33],[0.0,4.31,0.0],[0.0,4.51,3.33],[0.0,2.52,6.67],[0.0,1.3,10.0]],[[3.33,1.16,-10.0],[3.33,2.34,-6.67],[3.33,3.08,-3.33],[3.33,2.33,0.0],[3.33,1.74,3.33],[3.33,0.77,6.67],[3.33,0.97,10.0]],[[6.67,1.2,-10.0],[6.67,2.7,-6.67],[6.67,3.28,-3.33],[6.67,1.58,0.0],[6.67,0.99,3.33],[6.67,0.72,6.67],[6.67,0.95,10.0]],[[10.0,1.04,-10.0],[10.0,1.35,-6.67],[10.0,1.47,-3.33],[10.0,1.1,0.0],[10.0,1.0,3.33],[10.0,0.99,6.67],[10.0,1.0,10.0]]]"
},
"inputs": {},
"position": [
40,
40
]
},
"ground": {
"id": "ground",
"name": "bitbybit.occt.shapes.face.fromPointGrid",
"customName": "face from point grid",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"interpolate": true,
"periodic": false,
"degreeMin": 3,
"degreeMax": 8,
"tolerance": 0.001
},
"inputs": {
"points": {
"connections": [
{
"node": "survey",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"deep": {
"id": "deep",
"name": "bitbybit.occt.operations.extrude",
"customName": "extrude",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
-8,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "ground",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"square": {
"id": "square",
"name": "bitbybit.occt.shapes.solid.createBox",
"customName": "box",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 19,
"length": 19,
"height": 8,
"center": [
0,
4,
0
],
"originOnCenter": true
},
"inputs": {},
"position": [
40,
280
]
},
"pair": {
"id": "pair",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "deep",
"output": "result",
"data": {}
},
{
"node": "square",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"hill": {
"id": "hill",
"name": "bitbybit.occt.booleans.intersection",
"customName": "intersection",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"keepEdges": false
},
"inputs": {
"shapes": {
"connections": [
{
"node": "pair",
"output": "list",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"slices": {
"id": "slices",
"name": "bitbybit.occt.operations.slice",
"customName": "slice",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 0.5,
"direction": [
0,
1,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "hill",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"outlines": {
"id": "outlines",
"name": "bitbybit.occt.shapes.face.getFaces",
"customName": "get faces",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "slices",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
40
]
},
"plates": {
"id": "plates",
"name": "bitbybit.occt.operations.extrudeShapes",
"customName": "extrude shapes",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
0.42,
0
]
},
"inputs": {
"shapes": {
"connections": [
{
"node": "outlines",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
40
]
},
"plywood": {
"id": "plywood",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ffffff",
"vertexColour": "#ff00ff",
"edgeWidth": 1,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
666
]
},
"drawPlates": {
"id": "drawPlates",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "plates",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "plywood",
"output": "result",
"data": {}
}
]
}
},
"position": [
3400,
40
]
},
"view": {
"id": "view",
"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": [
18,
32,
-36
],
"lookAt": [
0,
2,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
3400,
334
]
}
},
"modules": {}
}

Lines across a surface​

A face has its own coordinates, U and V, running across it. wiresAlongParams draws a wire across the face at each value you give it, from 0 at one side to 1 at the other, and isU chooses the direction. Because the wires follow the surface they are a natural frame for it.

Here ten lines run each way across a roof and every one is piped into a beam with operations.pipeWiresCylindrical. The roof stays as a faint pane of glass:

Bitbybit Platform

A timber gridshell over a glass roof in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"points": {
"id": "points",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[[[-10.0,-1.23,-10.0],[-10.0,1.33,-6.0],[-10.0,2.61,-2.0],[-10.0,2.61,2.0],[-10.0,1.33,6.0],[-10.0,-1.23,10.0]],[[-6.0,0.45,-10.0],[-6.0,3.01,-6.0],[-6.0,4.29,-2.0],[-6.0,4.29,2.0],[-6.0,3.01,6.0],[-6.0,0.45,10.0]],[[-2.0,1.17,-10.0],[-2.0,3.73,-6.0],[-2.0,5.01,-2.0],[-2.0,5.01,2.0],[-2.0,3.73,6.0],[-2.0,1.17,10.0]],[[2.0,2.51,-10.0],[2.0,5.07,-6.0],[2.0,6.35,-2.0],[2.0,6.35,2.0],[2.0,5.07,6.0],[2.0,2.51,10.0]],[[6.0,0.67,-10.0],[6.0,3.23,-6.0],[6.0,4.51,-2.0],[6.0,4.51,2.0],[6.0,3.23,6.0],[6.0,0.67,10.0]],[[10.0,-2.77,-10.0],[10.0,-0.21,-6.0],[10.0,1.07,-2.0],[10.0,1.07,2.0],[10.0,-0.21,6.0],[10.0,-2.77,10.0]]]"
},
"inputs": {},
"position": [
40,
40
]
},
"roof": {
"id": "roof",
"name": "bitbybit.occt.shapes.face.fromPointGrid",
"customName": "face from point grid",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"interpolate": true,
"periodic": false,
"degreeMin": 3,
"degreeMax": 8,
"tolerance": 0.001
},
"inputs": {
"points": {
"connections": [
{
"node": "points",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"places": {
"id": "places",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[0, 0.111, 0.222, 0.333, 0.444, 0.556, 0.667, 0.778, 0.889, 1]"
},
"inputs": {},
"position": [
40,
280
]
},
"across": {
"id": "across",
"name": "bitbybit.occt.shapes.face.wiresAlongParams",
"customName": "wires along params",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"isU": true
},
"inputs": {
"shape": {
"connections": [
{
"node": "roof",
"output": "result",
"data": {}
}
]
},
"params": {
"connections": [
{
"node": "places",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"along": {
"id": "along",
"name": "bitbybit.occt.shapes.face.wiresAlongParams",
"customName": "wires along params",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"isU": false
},
"inputs": {
"shape": {
"connections": [
{
"node": "roof",
"output": "result",
"data": {}
}
]
},
"params": {
"connections": [
{
"node": "places",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
334
]
},
"beamsAcross": {
"id": "beamsAcross",
"name": "bitbybit.occt.operations.pipeWiresCylindrical",
"customName": "pipe wires cylindrical",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.1,
"makeSolid": true,
"trihedronEnum": "isConstantNormal",
"forceApproxC1": false,
"bendRadius": 0
},
"inputs": {
"shapes": {
"connections": [
{
"node": "across",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"beamsAlong": {
"id": "beamsAlong",
"name": "bitbybit.occt.operations.pipeWiresCylindrical",
"customName": "pipe wires cylindrical",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.1,
"makeSolid": true,
"trihedronEnum": "isConstantNormal",
"forceApproxC1": false,
"bendRadius": 0
},
"inputs": {
"shapes": {
"connections": [
{
"node": "along",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
472
]
},
"timber": {
"id": "timber",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ffffff",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": false,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
520
]
},
"glass": {
"id": "glass",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 0.3,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#9fd8ff",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": false,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": true,
"backFaceColour": "#9fd8ff",
"backFaceOpacity": 0.3,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
2470
]
},
"drawBeamsAcross": {
"id": "drawBeamsAcross",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "beamsAcross",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "timber",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"drawBeamsAlong": {
"id": "drawBeamsAlong",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "beamsAlong",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "timber",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
334
]
},
"drawRoof": {
"id": "drawRoof",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "roof",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "glass",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
628
]
},
"view": {
"id": "view",
"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": [
24,
24,
-34
],
"lookAt": [
0,
1,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
1720,
922
]
}
},
"modules": {}
}

isoCurves gives the same lines as exact edges trimmed to the face, and subdivideToWires spaces a given number of them evenly for you.

Skins over curves​

When you know the boundary of a surface and not its middle, stretch a skin over the curves.

  • boundaryPatch takes two, three or four edges. With three or four, style chooses the character of the skin: coons blends the edges, stretch is flatter and curved rounder.
  • fillPatch fills any closed loop of edges and can pass near points you give it. continuities says for each edge how the patch meets it: position only touches the edge, tangent and curvature also carry on smoothly from a face beside it, given in supports.
  • ruledBetween joins two edges or wires with straight lines from one to the other.

Both skins here span the same four arcs. The one on the right is pulled up through a point at height 7:

Bitbybit Platform

Two patches over the same four curves in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"north": {
"id": "north",
"name": "bitbybit.occt.shapes.edge.arcThroughThreePoints",
"customName": "arc through three points",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"start": [
0,
0,
0
],
"middle": [
5,
3,
0
],
"end": [
10,
0,
0
]
},
"inputs": {},
"position": [
40,
40
]
},
"east": {
"id": "east",
"name": "bitbybit.occt.shapes.edge.arcThroughThreePoints",
"customName": "arc through three points",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"start": [
10,
0,
0
],
"middle": [
12,
2,
5
],
"end": [
10,
0,
10
]
},
"inputs": {},
"position": [
40,
334
]
},
"south": {
"id": "south",
"name": "bitbybit.occt.shapes.edge.arcThroughThreePoints",
"customName": "arc through three points",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"start": [
10,
0,
10
],
"middle": [
5,
4,
10
],
"end": [
0,
0,
10
]
},
"inputs": {},
"position": [
40,
628
]
},
"west": {
"id": "west",
"name": "bitbybit.occt.shapes.edge.arcThroughThreePoints",
"customName": "arc through three points",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"start": [
0,
0,
10
],
"middle": [
-2,
2,
5
],
"end": [
0,
0,
0
]
},
"inputs": {},
"position": [
40,
922
]
},
"edges": {
"id": "edges",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "north",
"output": "result",
"data": {}
},
{
"node": "east",
"output": "result",
"data": {}
},
{
"node": "south",
"output": "result",
"data": {}
},
{
"node": "west",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"stretched": {
"id": "stretched",
"name": "bitbybit.occt.shapes.face.boundaryPatch",
"customName": "boundary patch",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"style": "coons"
},
"inputs": {
"edges": {
"connections": [
{
"node": "edges",
"output": "list",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"continuities": {
"id": "continuities",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[\"position\", \"position\", \"position\", \"position\"]"
},
"inputs": {},
"position": [
40,
1216
]
},
"peak": {
"id": "peak",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[[5, 7, 5]]"
},
"inputs": {},
"position": [
40,
1456
]
},
"pulled": {
"id": "pulled",
"name": "bitbybit.occt.shapes.face.fillPatch",
"customName": "fill patch",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"degree": 3,
"pointsOnCurves": 15,
"iterations": 2,
"tolerance": 0.0001
},
"inputs": {
"edges": {
"connections": [
{
"node": "edges",
"output": "list",
"data": {}
}
]
},
"continuities": {
"connections": [
{
"node": "continuities",
"output": "result",
"data": {}
}
]
},
"points": {
"connections": [
{
"node": "peak",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
288
]
},
"beside": {
"id": "beside",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
16,
0,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "pulled",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"skin": {
"id": "skin",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ffffff",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": true,
"backFaceColour": "#ffffff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
1696
]
},
"drawStretched": {
"id": "drawStretched",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "stretched",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "skin",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"drawBeside": {
"id": "drawBeside",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "beside",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "skin",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
334
]
},
"view": {
"id": "view",
"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": [
13,
26,
-34
],
"lookAt": [
13,
1,
5
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
1720,
628
]
}
},
"modules": {}
}

Patterns over a surface​

The subdivideTo functions spread a grid over a face. subdivideToPoints gives points, subdivideToNormals the directions there, and subdivideToFrames both at once, a frame on the surface at each spot with its normal square to it, which is what placeOnFrames wants. removeStartEdgeU, removeEndEdgeU and their two V partners leave out the rows along the face's edges, where a hole would break through:

Bitbybit Platform

A perforated panel on a curved surface in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"grid": {
"id": "grid",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[[[-10.0,-0.43,-6],[-10.0,-0.83,-4],[-10.0,-1.1,-2],[-10.0,-1.2,0],[-10.0,-1.1,2],[-10.0,-0.83,4],[-10.0,-0.43,6]],[[-7.5,-0.69,-6],[-7.5,-1.33,-4],[-7.5,-1.76,-2],[-7.5,-1.91,0],[-7.5,-1.76,2],[-7.5,-1.33,4],[-7.5,-0.69,6]],[[-5.0,-0.69,-6],[-5.0,-1.32,-4],[-5.0,-1.75,-2],[-5.0,-1.9,0],[-5.0,-1.75,2],[-5.0,-1.32,4],[-5.0,-0.69,6]],[[-2.5,-0.42,-6],[-2.5,-0.82,-4],[-2.5,-1.08,-2],[-2.5,-1.17,0],[-2.5,-1.08,2],[-2.5,-0.82,4],[-2.5,-0.42,6]],[[0.0,0.0,-6],[0.0,0.0,-4],[0.0,0.0,-2],[0.0,0.0,0],[0.0,0.0,2],[0.0,0.0,4],[0.0,0.0,6]],[[2.5,0.42,-6],[2.5,0.82,-4],[2.5,1.08,-2],[2.5,1.17,0],[2.5,1.08,2],[2.5,0.82,4],[2.5,0.42,6]],[[5.0,0.69,-6],[5.0,1.32,-4],[5.0,1.75,-2],[5.0,1.9,0],[5.0,1.75,2],[5.0,1.32,4],[5.0,0.69,6]],[[7.5,0.69,-6],[7.5,1.33,-4],[7.5,1.76,-2],[7.5,1.91,0],[7.5,1.76,2],[7.5,1.33,4],[7.5,0.69,6]],[[10.0,0.43,-6],[10.0,0.83,-4],[10.0,1.1,-2],[10.0,1.2,0],[10.0,1.1,2],[10.0,0.83,4],[10.0,0.43,6]]]"
},
"inputs": {},
"position": [
40,
40
]
},
"surface": {
"id": "surface",
"name": "bitbybit.occt.shapes.face.fromPointGrid",
"customName": "face from point grid",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"interpolate": true,
"periodic": false,
"degreeMin": 3,
"degreeMax": 8,
"tolerance": 0.001
},
"inputs": {
"points": {
"connections": [
{
"node": "grid",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"sheet": {
"id": "sheet",
"name": "bitbybit.occt.operations.makeThickSolidSimple",
"customName": "make thick solid simple",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"offset": -0.3
},
"inputs": {
"shape": {
"connections": [
{
"node": "surface",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"frames": {
"id": "frames",
"name": "bitbybit.occt.shapes.face.subdivideToFrames",
"customName": "subdivide to frames",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"nrDivisionsU": 9,
"nrDivisionsV": 7,
"shiftHalfStepU": false,
"removeStartEdgeU": true,
"removeEndEdgeU": true,
"shiftHalfStepV": false,
"removeStartEdgeV": true,
"removeEndEdgeV": true
},
"inputs": {
"shape": {
"connections": [
{
"node": "surface",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
288
]
},
"cutter": {
"id": "cutter",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.6,
"height": 3,
"center": [
0,
0,
-1.5
],
"direction": [
0,
0,
1
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
280
]
},
"cutters": {
"id": "cutters",
"name": "bitbybit.occt.transforms.placeOnFrames",
"customName": "place on frames",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "cutter",
"output": "result",
"data": {}
}
]
},
"frames": {
"connections": [
{
"node": "frames",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"tools": {
"id": "tools",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "cutters",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"panel": {
"id": "panel",
"name": "bitbybit.occt.booleans.difference",
"customName": "difference",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"keepEdges": false,
"strategy": "oneAfterAnother"
},
"inputs": {
"shape": {
"connections": [
{
"node": "sheet",
"output": "result",
"data": {}
}
]
},
"shapes": {
"connections": [
{
"node": "tools",
"output": "list",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"steel": {
"id": "steel",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {
"faceMaterial": {
"connections": [
{
"node": "steelMaterial",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
472
]
},
"steelMaterial": {
"id": "steelMaterial",
"name": "bitbybit.draw.createPBRMaterial",
"customName": "create pbr material",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"name": "PBRMaterial",
"baseColor": "#eef0f2",
"metallic": 0.7,
"roughness": 0.3,
"alpha": 1,
"emissiveColor": "#000000",
"emissiveIntensity": 1,
"zOffset": 0,
"zOffsetUnits": 0,
"alphaMode": "opaque",
"alphaCutoff": 0.5,
"doubleSided": false,
"wireframe": false,
"unlit": false
},
"inputs": {},
"position": [
40,
712
]
},
"drawPanel": {
"id": "drawPanel",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "panel",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "steel",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
40
]
},
"view": {
"id": "view",
"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": [
16,
20,
-22
],
"lookAt": [
0,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
2560,
334
]
}
},
"modules": {}
}

Flat shapes on a curved face​

Three functions take a flat outline to a curved face, and they differ in what they keep.

  • wrapWiresOnFace rolls it on and keeps every length, so it suits a label, a mark or a pattern on a plane, cylinder or cone. It works from the ground plane, with X around the cylinder and Z along its axis.
  • projectWires casts it along a direction, as the sun casts a shadow, and projectConical from a point, as a lamp does. Both work on any shape, and both stretch the outline where the surface turns away. A ray that misses the shape lands nowhere, so keep the outline inside what the lamp can reach.
Bitbybit Platform

Stars wrapped around a can in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"can": {
"id": "can",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 3,
"height": 8,
"center": [
0,
0,
0
],
"direction": [
1,
0,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
40
]
},
"walls": {
"id": "walls",
"name": "bitbybit.occt.select.faces.ofType",
"customName": "faces of type",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"type": "cylinder"
},
"inputs": {
"shape": {
"connections": [
{
"node": "can",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"wallIndex": {
"id": "wallIndex",
"name": "bitbybit.lists.getItem",
"customName": "get item",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0,
"clone": true
},
"inputs": {
"list": {
"connections": [
{
"node": "walls",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"wall": {
"id": "wall",
"name": "bitbybit.occt.shapes.face.getFace",
"customName": "get face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0
},
"inputs": {
"shape": {
"connections": [
{
"node": "can",
"output": "result",
"data": {}
}
]
},
"index": {
"connections": [
{
"node": "wallIndex",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"star1": {
"id": "star1",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
2.3,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
472
]
},
"star2": {
"id": "star2",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
5.44,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
950
]
},
"star3": {
"id": "star3",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
8.58,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
1428
]
},
"star4": {
"id": "star4",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
11.72,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
1906
]
},
"star5": {
"id": "star5",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
14.86,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
2384
]
},
"star6": {
"id": "star6",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
18,
0,
4
],
"direction": [
0,
1,
0
],
"numRays": 5,
"outerRadius": 1.2,
"innerRadius": 0.5,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
2862
]
},
"stars": {
"id": "stars",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "star1",
"output": "result",
"data": {}
},
{
"node": "star2",
"output": "result",
"data": {}
},
{
"node": "star3",
"output": "result",
"data": {}
},
{
"node": "star4",
"output": "result",
"data": {}
},
{
"node": "star5",
"output": "result",
"data": {}
},
{
"node": "star6",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
334
]
},
"wrapped": {
"id": "wrapped",
"name": "bitbybit.occt.shapes.wire.wrapWiresOnFace",
"customName": "wrap wires on face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 0.0001
},
"inputs": {
"wires": {
"connections": [
{
"node": "stars",
"output": "list",
"data": {}
}
]
},
"face": {
"connections": [
{
"node": "wall",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"labels": {
"id": "labels",
"name": "bitbybit.occt.shapes.face.createFacesFromWiresOnFace",
"customName": "faces from wires on face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"inside": true
},
"inputs": {
"wires": {
"connections": [
{
"node": "wrapped",
"output": "result",
"data": {}
}
]
},
"face": {
"connections": [
{
"node": "wall",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"drawnCan": {
"id": "drawnCan",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 2.97,
"height": 8,
"center": [
0,
0,
0
],
"direction": [
1,
0,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
3340
]
},
"brass": {
"id": "brass",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ff4400",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
3772
]
},
"drawDrawnCan": {
"id": "drawDrawnCan",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "drawnCan",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
40
]
},
"drawLabels": {
"id": "drawLabels",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "labels",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "brass",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
334
]
},
"view": {
"id": "view",
"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": [
4,
17,
-13
],
"lookAt": [
4,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
2560,
628
]
}
},
"modules": {}
}
Bitbybit Platform

A star cast onto a ball two ways in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"ball": {
"id": "ball",
"name": "bitbybit.occt.shapes.solid.createSphere",
"customName": "sphere",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 6,
"center": [
0,
0,
0
]
},
"inputs": {},
"position": [
40,
40
]
},
"star": {
"id": "star",
"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,
9,
0
],
"direction": [
0,
1,
0
],
"numRays": 6,
"outerRadius": 2.2,
"innerRadius": 1.1,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
288
]
},
"toCast": {
"id": "toCast",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "star",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"parallel": {
"id": "parallel",
"name": "bitbybit.occt.shapes.wire.projectWires",
"customName": "project wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
-1,
0
]
},
"inputs": {
"wires": {
"connections": [
{
"node": "toCast",
"output": "list",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "ball",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"parallelStar": {
"id": "parallelStar",
"name": "bitbybit.lists.getItem",
"customName": "get item",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0,
"clone": true
},
"inputs": {
"list": {
"connections": [
{
"node": "parallel",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"fromLamp": {
"id": "fromLamp",
"name": "bitbybit.occt.shapes.wire.projectConical",
"customName": "project conical",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"from": [
0,
14,
0
]
},
"inputs": {
"wire": {
"connections": [
{
"node": "star",
"output": "result",
"data": {}
}
]
},
"shape": {
"connections": [
{
"node": "ball",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
280
]
},
"sun": {
"id": "sun",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#ff6a00",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 4,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": true,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
766
]
},
"lamp": {
"id": "lamp",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#2f7fff",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 4,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": true,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
2716
]
},
"drawBall": {
"id": "drawBall",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "ball",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"drawStar": {
"id": "drawStar",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "star",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "sun",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
334
]
},
"drawParallel": {
"id": "drawParallel",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "parallelStar",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "sun",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
628
]
},
"drawFromLamp": {
"id": "drawFromLamp",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "fromLamp",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "lamp",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
922
]
},
"view": {
"id": "view",
"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,
30,
-17
],
"lookAt": [
0,
3,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
1720,
1216
]
}
},
"modules": {}
}

Laying a face flat​

unroll goes the other way, from a plane, cylinder or cone face to the flat sheet it can be bent from, keeping lengths and areas. The result lies on the ground plane, ready for a DXF export. Doubly curved faces, such as a sphere's, have no flat pattern and are refused:

Bitbybit Platform

The pattern a cone is cut from in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"cone": {
"id": "cone",
"name": "bitbybit.occt.shapes.solid.createCone",
"customName": "cone",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius1": 5,
"radius2": 2.5,
"height": 8,
"angle": 360,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
40
]
},
"drill": {
"id": "drill",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 1,
"height": 12,
"center": [
0,
3,
0
],
"direction": [
1,
0,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
472
]
},
"tools": {
"id": "tools",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "drill",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"drilled": {
"id": "drilled",
"name": "bitbybit.occt.booleans.difference",
"customName": "difference",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"keepEdges": false,
"strategy": "oneAfterAnother"
},
"inputs": {
"shape": {
"connections": [
{
"node": "cone",
"output": "result",
"data": {}
}
]
},
"shapes": {
"connections": [
{
"node": "tools",
"output": "list",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"sides": {
"id": "sides",
"name": "bitbybit.occt.select.faces.ofType",
"customName": "faces of type",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"type": "cone"
},
"inputs": {
"shape": {
"connections": [
{
"node": "drilled",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"sideIndex": {
"id": "sideIndex",
"name": "bitbybit.lists.getItem",
"customName": "get item",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0,
"clone": true
},
"inputs": {
"list": {
"connections": [
{
"node": "sides",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"side": {
"id": "side",
"name": "bitbybit.occt.shapes.face.getFace",
"customName": "get face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0
},
"inputs": {
"shape": {
"connections": [
{
"node": "drilled",
"output": "result",
"data": {}
}
]
},
"index": {
"connections": [
{
"node": "sideIndex",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"pattern": {
"id": "pattern",
"name": "bitbybit.occt.shapes.face.unroll",
"customName": "unroll",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 0.0001
},
"inputs": {
"shape": {
"connections": [
{
"node": "side",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
40
]
},
"beside": {
"id": "beside",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
12,
0,
-8
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "pattern",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
40
]
},
"steel": {
"id": "steel",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ffffff",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": true,
"backFaceColour": "#ffffff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
904
]
},
"drawDrilled": {
"id": "drawDrilled",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "drilled",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "steel",
"output": "result",
"data": {}
}
]
}
},
"position": [
3400,
40
]
},
"drawBeside": {
"id": "drawBeside",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "beside",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "steel",
"output": "result",
"data": {}
}
]
}
},
"position": [
3400,
334
]
},
"view": {
"id": "view",
"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,
50,
-42
],
"lookAt": [
10,
0,
-1
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
3400,
628
]
}
},
"modules": {}
}