Finding and repairing broken shapes
Most shapes you model are sound. Trouble tends to arrive with imported files, whose faces another program wrote to its own tolerances, and with faces you put together by hand. bitbybit.occt.shapeFix shows you what is wrong and puts it right.
Inside-out solids
A solid keeps its material on one side of its faces. If every face points the wrong way the material is on the outside: the volume comes out negative, and the viewer, which draws the back of a face in backFaceColour when the draw options ask for both sides with drawTwoSided, shows the whole solid blue.
Blue on its own proves nothing. A see-through solid shows the inside of its far walls the same way, and an open face shows its back from behind. A negative shapes.solid.getSolidVolume is the test, and it is worth knowing that isValid will not tell you: an inside-out solid is well formed, so it passes.
Here a drum is taken apart, its three faces are reversed and they are sewn back into a solid of volume -169.6. orientClosedSolid turns it into the drum beside it, at +169.6:
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"drum": {
"id": "drum",
"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": 6,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
40
]
},
"face0": {
"id": "face0",
"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": "drum",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"reversed0": {
"id": "reversed0",
"name": "bitbybit.occt.shapes.face.reversedFace",
"customName": "reversed face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "face0",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"face1": {
"id": "face1",
"name": "bitbybit.occt.shapes.face.getFace",
"customName": "get face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 1
},
"inputs": {
"shape": {
"connections": [
{
"node": "drum",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
288
]
},
"reversed1": {
"id": "reversed1",
"name": "bitbybit.occt.shapes.face.reversedFace",
"customName": "reversed face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "face1",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
280
]
},
"face2": {
"id": "face2",
"name": "bitbybit.occt.shapes.face.getFace",
"customName": "get face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 2
},
"inputs": {
"shape": {
"connections": [
{
"node": "drum",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
536
]
},
"reversed2": {
"id": "reversed2",
"name": "bitbybit.occt.shapes.face.reversedFace",
"customName": "reversed face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "face2",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
520
]
},
"reversed": {
"id": "reversed",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "reversed0",
"output": "result",
"data": {}
},
{
"node": "reversed1",
"output": "result",
"data": {}
},
{
"node": "reversed2",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"shell": {
"id": "shell",
"name": "bitbybit.occt.shapes.shell.sewFaces",
"customName": "sew faces",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7
},
"inputs": {
"shapes": {
"connections": [
{
"node": "reversed",
"output": "list",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"insideOut": {
"id": "insideOut",
"name": "bitbybit.occt.shapes.solid.fromClosedShell",
"customName": "from closed shell",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "shell",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"turned": {
"id": "turned",
"name": "bitbybit.occt.shapeFix.orientClosedSolid",
"customName": "orient closed solid",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "insideOut",
"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": [
8,
0,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "turned",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
40
]
},
"bright": {
"id": "bright",
"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": 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,
472
]
},
"drawInsideOut": {
"id": "drawInsideOut",
"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": "insideOut",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "bright",
"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": "bright",
"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": [
8,
15,
-25
],
"lookAt": [
4,
3,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
3400,
628
]
}
},
"modules": {}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="drum">drum</variable><variable id="insideOut">insideOut</variable><variable id="bright">bright</variable></variables><block type="variables_set" x="40" y="200"><field name="VAR" id="drum">drum</field><value name="VALUE"><block type="bitbybit.occt.shapes.solid.createCylinder"><value name="Radius"><block type="math_number"><field name="NUM">3</field></block></value><value name="Height"><block type="math_number"><field name="NUM">6</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Angle"><block type="math_number"><field name="NUM">360</field></block></value><value name="OriginOnCenter"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value><next><block type="variables_set"><field name="VAR" id="insideOut">insideOut</field><value name="VALUE"><block type="bitbybit.occt.shapes.solid.fromClosedShell"><value name="Shape"><block type="bitbybit.occt.shapes.shell.sewFaces"><value name="Shapes"><block type="lists_create_with"><mutation items="3"></mutation><value name="ADD0"><block type="bitbybit.occt.shapes.face.reversedFace"><value name="Shape"><block type="bitbybit.occt.shapes.face.getFace"><value name="Shape"><block type="variables_get"><field name="VAR" id="drum">drum</field></block></value><value name="Index"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><value name="ADD1"><block type="bitbybit.occt.shapes.face.reversedFace"><value name="Shape"><block type="bitbybit.occt.shapes.face.getFace"><value name="Shape"><block type="variables_get"><field name="VAR" id="drum">drum</field></block></value><value name="Index"><block type="math_number"><field name="NUM">1</field></block></value></block></value></block></value><value name="ADD2"><block type="bitbybit.occt.shapes.face.reversedFace"><value name="Shape"><block type="bitbybit.occt.shapes.face.getFace"><value name="Shape"><block type="variables_get"><field name="VAR" id="drum">drum</field></block></value><value name="Index"><block type="math_number"><field name="NUM">2</field></block></value></block></value></block></value></block></value><value name="Tolerance"><block type="math_number"><field name="NUM">1e-7</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="bright">bright</field><value name="VALUE"><block type="bitbybit.draw.optionsOcctShape"><value name="FaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeColour"><block type="colour_picker"><field name="COLOUR">#5f6773</field></block></value><value name="FaceColour"><block type="colour_picker"><field name="COLOUR">#ff4400</field></block></value><value name="VertexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="EdgeWidth"><block type="math_number"><field name="NUM">2</field></block></value><value name="EdgeWidthBySize"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="VertexSize"><block type="math_number"><field name="NUM">0.03</field></block></value><value name="DrawEdges"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawFaces"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawVertices"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.01</field></block></value><value name="AngularDeflection"><block type="math_number"><field name="NUM">0.5</field></block></value><value name="RelativeDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="PrecisionShare"><block type="math_number"><field name="NUM">0</field></block></value><value name="DrawEdgeIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="EdgeIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="EdgeIndexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="DrawFaceIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="FaceIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="FaceIndexColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="DrawTwoSided"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeArrowSize"><block type="math_number"><field name="NUM">0</field></block></value><value name="EdgeArrowAngle"><block type="math_number"><field name="NUM">15</field></block></value><value name="KeepMeshData"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="AllowQualityDecrease"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="ForceFaceDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="DrawIsoCurves"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="IsoCurvesU"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesV"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesColour"><block type="colour_picker"><field name="COLOUR">#808080</field></block></value><value name="SurfaceAnalysis"><block type="bitbybit.occt.enums.surfaceAnalysisEnum"><field name="bitbybit.occt.enums.surfaceAnalysisEnum">'none'</field></block></value><value name="DraftDirection"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="variables_get"><field name="VAR" id="insideOut">insideOut</field></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="bright">bright</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="bitbybit.occt.transforms.translate"><value name="Shape"><block type="bitbybit.occt.shapeFix.orientClosedSolid"><value name="Shape"><block type="variables_get"><field name="VAR" id="insideOut">insideOut</field></block></value></block></value><value name="Translation"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">8</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="bright">bright</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera"><value name="Position"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">8</field></block></value><value name="Y"><block type="math_number"><field name="NUM">15</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-25</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">4</field></block></value><value name="Y"><block type="math_number"><field name="NUM">3</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number"><field name="NUM">3</field></block></value></block></next></block></next></block></next></block></next></block></next></block></xml>
const drum = await bitbybit.occt.shapes.solid.createCylinder({ radius: 3, height: 6, center: [0, 0, 0], direction: [0, 1, 0] });
const faces = await bitbybit.occt.shapes.face.getFaces({ shape: drum });
const reversed = [];
for (const face of faces) {
reversed.push(await bitbybit.occt.shapes.face.reversedFace({ shape: face }));
}
const shell = await bitbybit.occt.shapes.shell.sewFaces({ shapes: reversed, tolerance: 1e-7 });
const insideOut = await bitbybit.occt.shapes.solid.fromClosedShell({ shape: shell });
const turned = await bitbybit.occt.shapeFix.orientClosedSolid({ shape: insideOut });
const beside = await bitbybit.occt.transforms.translate({ shape: turned, translation: [8, 0, 0] });
const bright = new Bit.Inputs.Draw.DrawOcctShapeOptions();
bright.faceColour = "#ff4400";
bright.edgeColour = "#5f6773";
bright.drawTwoSided = true;
await bitbybit.draw.drawAnyAsync({ entity: insideOut, options: bright });
await bitbybit.draw.drawAnyAsync({ entity: beside, options: bright });
bitbybit.babylon.scene.adjustActiveArcRotateCamera({ position: [8, 15, -25], lookAt: [4, 3, 0] });
To build a solid from faces you do not trust, reach for shapes.solid.fromFaces. It sews them and turns the result so its material is inside, which fromClosedShell does not do.
Both of these turn a solid by setting a flag on it, and tubes from pipeWireCylindrical and gears with a bore come out the same way. Such a solid measures and draws correctly and works in booleans, but filletEdges and chamferEdges lose the flag, and the result comes out broken with a negative volume. To round or chamfer one, sew its faces into a new solid first: shapes.face.getFaces, shapes.shell.sewFaces, then fromClosedShell.
Faces that do not quite meet
Sewing joins faces along edges that lie within a tolerance of each other. sewWithReport does the same job as shapes.shell.sewFaces and also says how it went: freeEdgeCount counts the edges left bounding a single face, contiguousEdgeCount the edges that were sewn together, and multipleEdgeCount the edges now shared by more than two faces.
freeBoundaries joins the free edges of a shape into wires, closed for those that close on themselves and open for the rest, so you can draw exactly where a shape is open.
These two sheets lie 0.02 apart. At a tolerance of 0.0000001 they stay two sheets with 8 free edges, and each keeps its own red loop. At 0.05 the middle edges are sewn, 6 free edges are left and one loop runs around the pair:
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"left": {
"id": "left",
"name": "bitbybit.occt.shapes.face.createSquareFace",
"customName": "square face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"size": 5,
"center": [
-2.51,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
40
]
},
"right": {
"id": "right",
"name": "bitbybit.occt.shapes.face.createSquareFace",
"customName": "square face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"size": 5,
"center": [
2.51,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
40,
334
]
},
"sheets": {
"id": "sheets",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "left",
"output": "result",
"data": {}
},
{
"node": "right",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"tight": {
"id": "tight",
"name": "bitbybit.occt.shapeFix.sewWithReport",
"customName": "sew with report",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7,
"nonManifold": false
},
"inputs": {
"shapes": {
"connections": [
{
"node": "sheets",
"output": "list",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"tightSheet": {
"id": "tightSheet",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "shape"
},
"inputs": {
"json": {
"connections": [
{
"node": "tight",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"tightRims": {
"id": "tightRims",
"name": "bitbybit.occt.shapeFix.freeBoundaries",
"customName": "free boundaries",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7
},
"inputs": {
"shape": {
"connections": [
{
"node": "tightSheet",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"tightLoops": {
"id": "tightLoops",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "closed"
},
"inputs": {
"json": {
"connections": [
{
"node": "tightRims",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"loose": {
"id": "loose",
"name": "bitbybit.occt.shapeFix.sewWithReport",
"customName": "sew with report",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 0.05,
"nonManifold": false
},
"inputs": {
"shapes": {
"connections": [
{
"node": "sheets",
"output": "list",
"data": {}
}
]
}
},
"position": [
880,
334
]
},
"looseSheet": {
"id": "looseSheet",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "shape"
},
"inputs": {
"json": {
"connections": [
{
"node": "loose",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
288
]
},
"moved": {
"id": "moved",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
0,
0,
7
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "looseSheet",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
288
]
},
"looseRims": {
"id": "looseRims",
"name": "bitbybit.occt.shapeFix.freeBoundaries",
"customName": "free boundaries",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 1e-7
},
"inputs": {
"shape": {
"connections": [
{
"node": "moved",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
288
]
},
"looseLoops": {
"id": "looseLoops",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "closed"
},
"inputs": {
"json": {
"connections": [
{
"node": "looseRims",
"output": "result",
"data": {}
}
]
}
},
"position": [
2560,
40
]
},
"sheet": {
"id": "sheet",
"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": 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,
628
]
},
"rim": {
"id": "rim",
"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": "#ff2020",
"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,
2578
]
},
"drawTightSheet": {
"id": "drawTightSheet",
"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": "tightSheet",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "sheet",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
40
]
},
"drawTightLoops": {
"id": "drawTightLoops",
"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": "tightLoops",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "rim",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
334
]
},
"drawMoved": {
"id": "drawMoved",
"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": "moved",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "sheet",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
628
]
},
"drawLooseLoops": {
"id": "drawLooseLoops",
"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": "looseLoops",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "rim",
"output": "result",
"data": {}
}
]
}
},
"position": [
2980,
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": [
0,
17,
-11
],
"lookAt": [
0,
0,
3.5
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
2980,
1216
]
}
},
"modules": {}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="sheets">sheets</variable><variable id="tight">tight</variable><variable id="tightSheet">tightSheet</variable><variable id="tightRims">tightRims</variable><variable id="loose">loose</variable><variable id="moved">moved</variable><variable id="looseRims">looseRims</variable><variable id="sheet">sheet</variable><variable id="rim">rim</variable></variables><block type="variables_set" x="40" y="200"><field name="VAR" id="sheets">sheets</field><value name="VALUE"><block type="lists_create_with"><mutation items="2"></mutation><value name="ADD0"><block type="bitbybit.occt.shapes.face.createSquareFace"><value name="Size"><block type="math_number"><field name="NUM">5</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">-2.51</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><value name="ADD1"><block type="bitbybit.occt.shapes.face.createSquareFace"><value name="Size"><block type="math_number"><field name="NUM">5</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">2.51</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="tight">tight</field><value name="VALUE"><block type="base_time_await_return"><value name="Promise"><block type="bitbybit.occt.shapeFix.sewWithReport"><value name="Shapes"><block type="variables_get"><field name="VAR" id="sheets">sheets</field></block></value><value name="Tolerance"><block type="math_number"><field name="NUM">1e-7</field></block></value><value name="NonManifold"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="tightSheet">tightSheet</field><value name="VALUE"><block type="bitbybit.json.getValueOnProp"><value name="Json"><block type="variables_get"><field name="VAR" id="tight">tight</field></block></value><value name="Property"><block type="text"><field name="TEXT">shape</field></block></value></block></value><next><block type="variables_set"><field name="VAR" id="tightRims">tightRims</field><value name="VALUE"><block type="base_time_await_return"><value name="Promise"><block type="bitbybit.occt.shapeFix.freeBoundaries"><value name="Shape"><block type="variables_get"><field name="VAR" id="tightSheet">tightSheet</field></block></value><value name="Tolerance"><block type="math_number"><field name="NUM">1e-7</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="loose">loose</field><value name="VALUE"><block type="base_time_await_return"><value name="Promise"><block type="bitbybit.occt.shapeFix.sewWithReport"><value name="Shapes"><block type="variables_get"><field name="VAR" id="sheets">sheets</field></block></value><value name="Tolerance"><block type="math_number"><field name="NUM">0.05</field></block></value><value name="NonManifold"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="moved">moved</field><value name="VALUE"><block type="bitbybit.occt.transforms.translate"><value name="Shape"><block type="bitbybit.json.getValueOnProp"><value name="Json"><block type="variables_get"><field name="VAR" id="loose">loose</field></block></value><value name="Property"><block type="text"><field name="TEXT">shape</field></block></value></block></value><value name="Translation"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">7</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="looseRims">looseRims</field><value name="VALUE"><block type="base_time_await_return"><value name="Promise"><block type="bitbybit.occt.shapeFix.freeBoundaries"><value name="Shape"><block type="variables_get"><field name="VAR" id="moved">moved</field></block></value><value name="Tolerance"><block type="math_number"><field name="NUM">1e-7</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="sheet">sheet</field><value name="VALUE"><block type="bitbybit.draw.optionsOcctShape"><value name="FaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeColour"><block type="colour_picker"><field name="COLOUR">#5f6773</field></block></value><value name="FaceColour"><block type="colour_picker"><field name="COLOUR">#ffffff</field></block></value><value name="VertexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="EdgeWidth"><block type="math_number"><field name="NUM">2</field></block></value><value name="EdgeWidthBySize"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="VertexSize"><block type="math_number"><field name="NUM">0.03</field></block></value><value name="DrawEdges"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="DrawFaces"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawVertices"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.01</field></block></value><value name="AngularDeflection"><block type="math_number"><field name="NUM">0.5</field></block></value><value name="RelativeDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="PrecisionShare"><block type="math_number"><field name="NUM">0</field></block></value><value name="DrawEdgeIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="EdgeIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="EdgeIndexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="DrawFaceIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="FaceIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="FaceIndexColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="DrawTwoSided"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker"><field name="COLOUR">#ffffff</field></block></value><value name="BackFaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeArrowSize"><block type="math_number"><field name="NUM">0</field></block></value><value name="EdgeArrowAngle"><block type="math_number"><field name="NUM">15</field></block></value><value name="KeepMeshData"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="AllowQualityDecrease"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="ForceFaceDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="DrawIsoCurves"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="IsoCurvesU"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesV"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesColour"><block type="colour_picker"><field name="COLOUR">#808080</field></block></value><value name="SurfaceAnalysis"><block type="bitbybit.occt.enums.surfaceAnalysisEnum"><field name="bitbybit.occt.enums.surfaceAnalysisEnum">'none'</field></block></value><value name="DraftDirection"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set"><field name="VAR" id="rim">rim</field><value name="VALUE"><block type="bitbybit.draw.optionsOcctShape"><value name="FaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeColour"><block type="colour_picker"><field name="COLOUR">#ff2020</field></block></value><value name="FaceColour"><block type="colour_picker"><field name="COLOUR">#ff0000</field></block></value><value name="VertexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="EdgeWidth"><block type="math_number"><field name="NUM">4</field></block></value><value name="EdgeWidthBySize"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="VertexSize"><block type="math_number"><field name="NUM">0.03</field></block></value><value name="DrawEdges"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawFaces"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawVertices"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.01</field></block></value><value name="AngularDeflection"><block type="math_number"><field name="NUM">0.5</field></block></value><value name="RelativeDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="PrecisionShare"><block type="math_number"><field name="NUM">0</field></block></value><value name="DrawEdgeIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="EdgeIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="EdgeIndexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="DrawFaceIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="FaceIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="FaceIndexColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="DrawTwoSided"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeArrowSize"><block type="math_number"><field name="NUM">0</field></block></value><value name="EdgeArrowAngle"><block type="math_number"><field name="NUM">15</field></block></value><value name="KeepMeshData"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="AllowQualityDecrease"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="ForceFaceDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="DrawIsoCurves"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="IsoCurvesU"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesV"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesColour"><block type="colour_picker"><field name="COLOUR">#808080</field></block></value><value name="SurfaceAnalysis"><block type="bitbybit.occt.enums.surfaceAnalysisEnum"><field name="bitbybit.occt.enums.surfaceAnalysisEnum">'none'</field></block></value><value name="DraftDirection"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="variables_get"><field name="VAR" id="tightSheet">tightSheet</field></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="sheet">sheet</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="bitbybit.json.getValueOnProp"><value name="Json"><block type="variables_get"><field name="VAR" id="tightRims">tightRims</field></block></value><value name="Property"><block type="text"><field name="TEXT">closed</field></block></value></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="rim">rim</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="variables_get"><field name="VAR" id="moved">moved</field></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="sheet">sheet</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="bitbybit.json.getValueOnProp"><value name="Json"><block type="variables_get"><field name="VAR" id="looseRims">looseRims</field></block></value><value name="Property"><block type="text"><field name="TEXT">closed</field></block></value></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="rim">rim</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera"><value name="Position"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">17</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-11</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">3.5</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number"><field name="NUM">3</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>
const left = await bitbybit.occt.shapes.face.createSquareFace({ size: 5, center: [-2.51, 0, 0], direction: [0, 1, 0] });
const right = await bitbybit.occt.shapes.face.createSquareFace({ size: 5, center: [2.51, 0, 0], direction: [0, 1, 0] });
const tight = await bitbybit.occt.shapeFix.sewWithReport({ shapes: [left, right], tolerance: 1e-7, nonManifold: false });
const tightRims = await bitbybit.occt.shapeFix.freeBoundaries({ shape: tight.shape, tolerance: 1e-7 });
const loose = await bitbybit.occt.shapeFix.sewWithReport({ shapes: [left, right], tolerance: 0.05, nonManifold: false });
const moved = await bitbybit.occt.transforms.translate({ shape: loose.shape, translation: [0, 0, 7] });
const looseRims = await bitbybit.occt.shapeFix.freeBoundaries({ shape: moved, tolerance: 1e-7 });
const sheet = new Bit.Inputs.Draw.DrawOcctShapeOptions();
sheet.faceColour = "#ffffff";
sheet.edgeColour = "#5f6773";
sheet.drawTwoSided = true;
sheet.backFaceColour = "#ffffff";
sheet.drawEdges = false;
const rim = new Bit.Inputs.Draw.DrawOcctShapeOptions();
rim.edgeColour = "#ff2020";
rim.edgeWidth = 4;
await bitbybit.draw.drawAnyAsync({ entity: tight.shape, options: sheet });
await bitbybit.draw.drawAnyAsync({ entity: tightRims.closed, options: rim });
await bitbybit.draw.drawAnyAsync({ entity: moved, options: sheet });
await bitbybit.draw.drawAnyAsync({ entity: looseRims.closed, options: rim });
bitbybit.babylon.scene.adjustActiveArcRotateCamera({ position: [0, 17, -11], lookAt: [0, 0, 3.5] });
Use a tolerance a little larger than the widest gap. One much larger can join edges that were never meant to meet.
Checking a shape
isValid answers yes or no. validityReport gives the detail: isValid, a list of faults naming each faulty sub-shape and the checks it fails, and the smallest, largest and average tolerance found in the shape.
A valid shape is well formed, which is not the same as being the shape you meant. After a risky operation, compare its volume with what you expect as well.
The repair functions
| Function | What it does |
|---|---|
orientClosedSolid | Turns a closed solid so its material is inside |
fixSolid | Repairs a solid, or makes one from a closed shell, with its shells fixed and turned the right way |
fixShell | Turns the faces of a shell so they all face the same way, and fixes its faces and edges |
basicShapeRepair | Runs the kernel's general repair over a shape: small gaps, wire and face defects |
fixSmallEdgeOnWire | Removes edges shorter than a size from a wire and closes the gaps they leave |
fixEdgeOrientationsAlongWire | Rebuilds a wire so its edges run head to tail in one direction |



