Technical drawings from a model
A technical drawing shows a part from one direction as lines: the edges the eye sees, and often the edges hidden behind faces, drawn thinner or dashed. bitbybit.occt.operations.hiddenLines makes that drawing from any shape and any view, flat on the ground plane, ready to draw in the scene or to export as SVG or DXF.
Here a box with a hole through it is seen from a corner. The drawing lies on the ground in front of the part, its visible edges white and thick and its hidden edges thin and grey:
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"box": {
"id": "box",
"name": "bitbybit.occt.shapes.solid.createBox",
"customName": "box",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 4,
"length": 3,
"height": 2,
"center": [
0,
1,
-6
],
"originOnCenter": true
},
"inputs": {},
"position": [
40,
40
]
},
"hole": {
"id": "hole",
"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.5,
-6
],
"direction": [
0,
1,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
520
]
},
"tools": {
"id": "tools",
"name": "bitbybit.lists.createList",
"customName": "create list",
"async": false,
"drawable": false,
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "hole",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
520
]
},
"part": {
"id": "part",
"name": "bitbybit.occt.booleans.difference",
"customName": "difference",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"keepEdges": false,
"strategy": "oneAfterAnother"
},
"inputs": {
"shape": {
"connections": [
{
"node": "box",
"output": "result",
"data": {}
}
]
},
"shapes": {
"connections": [
{
"node": "tools",
"output": "list",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"view": {
"id": "view",
"name": "bitbybit.frame.create",
"customName": "frame",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"origin": [
0,
1,
-6
],
"normal": [
1,
1,
1
],
"direction": [
1,
0,
-1
]
},
"inputs": {},
"position": [
460,
800
]
},
"drawing": {
"id": "drawing",
"name": "bitbybit.occt.operations.hiddenLines",
"customName": "hidden lines",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"exact": true,
"smoothEdges": false,
"hiddenEdges": true,
"focus": 0,
"precision": 0.01
},
"inputs": {
"shape": {
"connections": [
{
"node": "part",
"output": "result",
"data": {}
}
]
},
"frame": {
"connections": [
{
"node": "view",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"visible": {
"id": "visible",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "visible"
},
"inputs": {
"json": {
"connections": [
{
"node": "drawing",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"hidden": {
"id": "hidden",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "hidden"
},
"inputs": {
"json": {
"connections": [
{
"node": "drawing",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
400
]
},
"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": "#ffffff",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 3,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"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": [
1300,
760
]
},
"drawVisible": {
"id": "drawVisible",
"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": "visible",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "bright",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"grey": {
"id": "grey",
"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": "#7a7a7a",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 1,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"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": [
1720,
760
]
},
"drawHidden": {
"id": "drawHidden",
"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": "hidden",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "grey",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
400
]
}
},
"modules": {}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="part">part</variable><variable id="drawing">drawing</variable></variables><block type="variables_set" x="40" y="40"><field name="VAR" id="part">part</field><value name="VALUE"><block type="bitbybit.occt.booleans.difference"><value name="Shape"><block type="bitbybit.occt.shapes.solid.createBox"><value name="Width"><block type="math_number"><field name="NUM">4</field></block></value><value name="Length"><block type="math_number"><field name="NUM">3</field></block></value><value name="Height"><block type="math_number"><field name="NUM">2</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">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-6</field></block></value></block></value><value name="OriginOnCenter"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value></block></value><value name="Shapes"><block type="bitbybit.lists.addItem"><value name="List"><block type="bitbybit.lists.createEmptyList"></block></value><value name="Item"><block type="bitbybit.occt.shapes.solid.createCylinder"><value name="Radius"><block type="math_number"><field name="NUM">0.6</field></block></value><value name="Height"><block type="math_number"><field name="NUM">3</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.5</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-6</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><value name="Clone"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value></block></value><value name="KeepEdges"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Strategy"><block type="bitbybit.occt.enums.booleanStrategyEnum"><field name="bitbybit.occt.enums.booleanStrategyEnum">'oneAfterAnother'</field></block></value></block></value><next><block type="variables_set"><field name="VAR" id="drawing">drawing</field><value name="VALUE"><block type="base_time_await_return"><value name="Promise"><block type="bitbybit.occt.operations.hiddenLines"><value name="Shape"><block type="variables_get"><field name="VAR" id="part">part</field></block></value><value name="Frame"><block type="bitbybit.frame.create"><value name="Origin"><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">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-6</field></block></value></block></value><value name="Normal"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">1</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">1</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">1</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">-1</field></block></value></block></value></block></value><value name="Exact"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="SmoothEdges"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="HiddenEdges"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="Focus"><block type="math_number"><field name="NUM">0</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.01</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="variables_get"><field name="VAR" id="part">part</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="drawing">drawing</field></block></value><value name="Property"><block type="text"><field name="TEXT">visible</field></block></value></block></value><value name="Options"><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">#ffffff</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">3</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="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="bitbybit.json.getValueOnProp"><value name="Json"><block type="variables_get"><field name="VAR" id="drawing">drawing</field></block></value><value name="Property"><block type="text"><field name="TEXT">hidden</field></block></value></block></value><value name="Options"><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">#7a7a7a</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">1</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="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></block></next></block></next></block></next></block></next></block></xml>
const box = await bitbybit.occt.shapes.solid.createBox({ width: 4, length: 3, height: 2, center: [0, 1, -6] });
const hole = await bitbybit.occt.shapes.solid.createCylinder({ radius: 0.6, height: 3, center: [0, -0.5, -6] });
const part = await bitbybit.occt.booleans.difference({ shape: box, shapes: [hole], keepEdges: false });
const view = bitbybit.frame.create({ origin: [0, 1, -6], normal: [1, 1, 1], direction: [1, 0, -1] });
const drawing = await bitbybit.occt.operations.hiddenLines({ shape: part, frame: view });
const bright = new Bit.Inputs.Draw.DrawOcctShapeOptions();
bright.edgeColour = "#ffffff";
bright.edgeWidth = 3;
const grey = new Bit.Inputs.Draw.DrawOcctShapeOptions();
grey.edgeColour = "#7a7a7a";
grey.edgeWidth = 1;
await bitbybit.draw.drawAnyAsync({ entity: part });
await bitbybit.draw.drawAnyAsync({ entity: drawing.visible, options: bright });
await bitbybit.draw.drawAnyAsync({ entity: drawing.hidden, options: grey });
The view
The view is a frame (see Frames). The eye sits on the side the frame's normal points to and looks back along it, and the drawing's x runs along the frame's direction. A normal of [0, 0, 1] gives a front view, [0, 1, 0] a plan from above, [1, 1, 1] the corner view of the example. The drawing is centered on the frame's origin, so put the origin at the part's middle.
hiddenLines returns two compounds of edges: visible and hidden. Its options:
hiddenEdges(true) collects the hidden edges; with false,hiddenstays empty.smoothEdges(false) also draws the edges where faces meet without a crease, such as the borders of a fillet.focus(0) gives a perspective view from that distance; 0 is a parallel view, as technical drawings use.exact(true) works from the exact geometry; false works from a mesh, which is faster for big models and draws parallel views only.
SVG
bitbybit.occt.io.saveShapeSvg draws the same view straight into an SVG file and downloads it, with the hidden edges dashed when drawHidden is true. saveShapeSvgAndReturn returns the SVG text as well, to show on a page or send elsewhere. Both take the shape and the frame, not the result of hiddenLines.
DXF
The drawing lies flat on the ground plane, which is what the DXF export needs. Turn each compound into paths with bitbybit.occt.io.shapeToDxfPaths, put each on its own layer with dxfPathsWithLayer (the visible edges on one layer in black, the hidden ones on another in grey) and write the file with dxfCreate. CAD programs then show, hide or restyle each layer. DXF drawings walks through the DXF steps on text and patterns.
Sections through a part, which drawings often show beside the views, are on Sections and slices.



