Creating Wires from Edges
Combining edges into a wire is one of the most fundamental operations in 3D modeling and computational geometry. While individual edges represent simple geometric elements like lines, arcs, or splines, wires allow us to connect these edges into more complex, continuous shapes that form the backbone of sophisticated geometric models.
Why Combine Edges into Wires?
In practical 3D modeling scenarios, you rarely work with isolated geometric elements. Instead, you need to create connected paths, profiles, and contours that can serve various purposes:
- Creating complex profiles for extrusion or sweeping operations
- Building wireframe models that define the skeleton of 3D objects
- Generating paths for manufacturing tools, robot movements, or animation curves
- Forming closed loops that can later be converted into faces and surfaces
- Constructing architectural elements like floor plans, structural frameworks, or decorative patterns
The Power of Edge Combination
When you combine individual edges into a wire, you gain several important capabilities:
1. Continuity Control
OCCT automatically ensures that edges connect properly at their endpoints, maintaining geometric continuity throughout the wire.
2. Complex Shape Creation
By combining different types of edges (lines, arcs, splines), you can create sophisticated shapes that would be impossible to achieve with single geometric primitives.
3. Topology Management
Wires maintain the topological relationships between edges, making them suitable for advanced operations like face creation, boolean operations, and geometric analysis.
4. Manufacturing Applications
Combined wires can represent tool paths, cutting profiles, or assembly sequences in manufacturing and CAD applications.
Understanding the Example
In this tutorial, we'll demonstrate edge combination by creating a flower-like pattern from four arc segments. The process involves:
- Creating a base arc through three specific points
- Generating variations by rotating the base arc in 90-degree increments
- Combining all arcs into a single, continuous wire structure
This example showcases how simple geometric operations (arc creation and rotation) can be combined with wire operations to create complex, aesthetically pleasing shapes that would be challenging to define manually.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"d3eae5ce6dc65c7d": {
"id": "d3eae5ce6dc65c7d",
"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": [
0,
1,
0
],
"end": [
0,
0,
1
]
},
"inputs": {
"start": {
"connections": [
{
"node": "b0c0c10ad0f0b376",
"output": "result",
"data": {}
}
]
},
"middle": {
"connections": [
{
"node": "b0f0ab88ce56530b",
"output": "result",
"data": {}
}
]
},
"end": {
"connections": [
{
"node": "eb556be1eebab3e1",
"output": "result",
"data": {}
}
]
}
},
"position": [
534.1448402109038,
379.3579836100596
]
},
"b0c0c10ad0f0b376": {
"id": "b0c0c10ad0f0b376",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 5,
"y": 0,
"z": 5
},
"inputs": {},
"position": [
94.57403303556532,
90.44351868458702
]
},
"b0f0ab88ce56530b": {
"id": "b0f0ab88ce56530b",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 3
},
"inputs": {},
"position": [
89.45148079042713,
428.0205711278293
]
},
"eb556be1eebab3e1": {
"id": "eb556be1eebab3e1",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": -5,
"y": 0,
"z": 5
},
"inputs": {},
"position": [
96.3359847306213,
789.091745319537
]
},
"813ef50a24796266": {
"id": "813ef50a24796266",
"name": "bitbybit.occt.transforms.rotate",
"customName": "rotate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"axis": [
0,
0,
1
],
"angle": 90
},
"inputs": {
"shape": {
"connections": [
{
"node": "d3eae5ce6dc65c7d",
"output": "result",
"data": {}
}
]
},
"axis": {
"connections": [
{
"node": "639ad3b9d7d8fb96",
"output": "result",
"data": {}
}
]
}
},
"position": [
979.2191844359841,
528.0582678468946
]
},
"639ad3b9d7d8fb96": {
"id": "639ad3b9d7d8fb96",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 1,
"z": 0
},
"inputs": {},
"position": [
544.652073196799,
1052.9517323029297
]
},
"83256d1d59d91e85": {
"id": "83256d1d59d91e85",
"name": "bitbybit.occt.transforms.rotate",
"customName": "rotate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"axis": [
0,
0,
1
],
"angle": 90
},
"inputs": {
"shape": {
"connections": [
{
"node": "813ef50a24796266",
"output": "result",
"data": {}
}
]
},
"axis": {
"connections": [
{
"node": "639ad3b9d7d8fb96",
"output": "result",
"data": {}
}
]
}
},
"position": [
1396.0370000621306,
710.2873028136673
]
},
"46a4c9a430a67a38": {
"id": "46a4c9a430a67a38",
"name": "bitbybit.occt.transforms.rotate",
"customName": "rotate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"axis": [
0,
0,
1
],
"angle": 90
},
"inputs": {
"shape": {
"connections": [
{
"node": "83256d1d59d91e85",
"output": "result",
"data": {}
}
]
},
"axis": {
"connections": [
{
"node": "639ad3b9d7d8fb96",
"output": "result",
"data": {}
}
]
}
},
"position": [
1779.8751584275665,
993.0350632431747
]
},
"d9118ec2955d5d74": {
"id": "d9118ec2955d5d74",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "d3eae5ce6dc65c7d",
"output": "result",
"data": {}
},
{
"node": "813ef50a24796266",
"output": "result",
"data": {}
},
{
"node": "83256d1d59d91e85",
"output": "result",
"data": {}
},
{
"node": "46a4c9a430a67a38",
"output": "result",
"data": {}
}
]
}
},
"position": [
2251.1631148261968,
392.62231116107625
]
},
"4aa103865a33f040": {
"id": "4aa103865a33f040",
"name": "bitbybit.occt.shapes.wire.combineEdgesAndWiresIntoAWire",
"customName": "combine edges and wires into a wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shapes": {
"connections": [
{
"node": "d9118ec2955d5d74",
"output": "list",
"data": {}
}
]
}
},
"position": [
2635.0126636293408,
351.4568381003743
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="arc1">arc1</variable><variable id="arc2">arc2</variable><variable id="arc3">arc3</variable><variable id="arc4">arc4</variable><variable id="edgesList">edgesList</variable><variable id="combinedWire">combinedWire</variable></variables><block type="variables_set" id="create_arc1" x="50" y="50"><field name="VAR" id="arc1">arc1</field><value name="VALUE"><block type="bitbybit.occt.shapes.edge.arcThroughThreePoints" id="arc_through_three_points"><value name="Start"><block type="bitbybit.point.pointXYZ" id="arc_start"><value name="X"><block type="math_number" id="start_x"><field name="NUM">5</field></block></value><value name="Y"><block type="math_number" id="start_y"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="start_z"><field name="NUM">5</field></block></value></block></value><value name="Middle"><block type="bitbybit.point.pointXYZ" id="arc_middle"><value name="X"><block type="math_number" id="middle_x"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="middle_y"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="middle_z"><field name="NUM">3</field></block></value></block></value><value name="End"><block type="bitbybit.point.pointXYZ" id="arc_end"><value name="X"><block type="math_number" id="end_x"><field name="NUM">-5</field></block></value><value name="Y"><block type="math_number" id="end_y"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="end_z"><field name="NUM">5</field></block></value></block></value></block></value><next><block type="variables_set" id="create_arc2" x="50" y="150"><field name="VAR" id="arc2">arc2</field><value name="VALUE"><block type="bitbybit.occt.transforms.rotate" id="rotate_arc_90_1"><value name="Shape"><block type="variables_get" id="get_arc1_for_rotate"><field name="VAR" id="arc1">arc1</field></block></value><value name="Axis"><block type="bitbybit.vector.vectorXYZ" id="rotation_axis_1"><value name="X"><block type="math_number" id="axis_x_1"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="axis_y_1"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="axis_z_1"><field name="NUM">0</field></block></value></block></value><value name="Angle"><block type="math_number" id="rotation_angle_1"><field name="NUM">90</field></block></value></block></value><next><block type="variables_set" id="create_arc3" x="50" y="250"><field name="VAR" id="arc3">arc3</field><value name="VALUE"><block type="bitbybit.occt.transforms.rotate" id="rotate_arc_90_2"><value name="Shape"><block type="variables_get" id="get_arc2_for_rotate"><field name="VAR" id="arc2">arc2</field></block></value><value name="Axis"><block type="bitbybit.vector.vectorXYZ" id="rotation_axis_2"><value name="X"><block type="math_number" id="axis_x_2"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="axis_y_2"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="axis_z_2"><field name="NUM">0</field></block></value></block></value><value name="Angle"><block type="math_number" id="rotation_angle_2"><field name="NUM">90</field></block></value></block></value><next><block type="variables_set" id="create_arc4" x="50" y="350"><field name="VAR" id="arc4">arc4</field><value name="VALUE"><block type="bitbybit.occt.transforms.rotate" id="rotate_arc_90_3"><value name="Shape"><block type="variables_get" id="get_arc3_for_rotate"><field name="VAR" id="arc3">arc3</field></block></value><value name="Axis"><block type="bitbybit.vector.vectorXYZ" id="rotation_axis_3"><value name="X"><block type="math_number" id="axis_x_3"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="axis_y_3"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="axis_z_3"><field name="NUM">0</field></block></value></block></value><value name="Angle"><block type="math_number" id="rotation_angle_3"><field name="NUM">90</field></block></value></block></value><next><block type="variables_set" id="create_edges_list" x="50" y="450"><field name="VAR" id="edgesList">edgesList</field><value name="VALUE"><block type="lists_create_with" id="create_list_with_arcs"><mutation items="4"></mutation><value name="ADD0"><block type="variables_get" id="get_arc1_for_list"><field name="VAR" id="arc1">arc1</field></block></value><value name="ADD1"><block type="variables_get" id="get_arc2_for_list"><field name="VAR" id="arc2">arc2</field></block></value><value name="ADD2"><block type="variables_get" id="get_arc3_for_list"><field name="VAR" id="arc3">arc3</field></block></value><value name="ADD3"><block type="variables_get" id="get_arc4_for_list"><field name="VAR" id="arc4">arc4</field></block></value></block></value><next><block type="variables_set" id="combine_edges_into_wire" x="50" y="550"><field name="VAR" id="combinedWire">combinedWire</field><value name="VALUE"><block type="bitbybit.occt.shapes.wire.combineEdgesAndWiresIntoAWire" id="combine_edges_wire"><value name="Shapes"><block type="variables_get" id="get_edges_list"><field name="VAR" id="edgesList">edgesList</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="draw_combined_wire" x="50" y="650"><value name="Entity"><block type="variables_get" id="get_combined_wire"><field name="VAR" id="combinedWire">combinedWire</field></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs and types for edge and wire creation
const { ArcEdgeThreePointsDto, RotateDto, ShapesDto } = Bit.Inputs.OCCT;
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
type TopoDSShapePointer = Bit.Inputs.OCCT.TopoDSShapePointer;
type TopoDSEdgePointer = Bit.Inputs.OCCT.TopoDSEdgePointer;
// Get access to OCCT edge, wire, and transform functions
const { edge, wire } = bitbybit.occt.shapes;
const { transforms } = bitbybit.occt;
// Define the main function to create a wire from multiple edges
const start = async () => {
// Create the first arc through three points
const arcOptions = new ArcEdgeThreePointsDto();
arcOptions.start = [5, 0, 5] as Point3;
arcOptions.middle = [0, 0, 3] as Point3;
arcOptions.end = [-5, 0, 5] as Point3;
const arc1 = await edge.arcThroughThreePoints(arcOptions);
// Create rotation options for Y-axis rotation
const rotateOptions = new RotateDto<TopoDSShapePointer>();
rotateOptions.axis = [0, 1, 0] as Vector3;
rotateOptions.angle = 90; // 90 degrees
// Create three more arcs by rotating the first arc
rotateOptions.shape = arc1;
const arc2 = await transforms.rotate(rotateOptions);
rotateOptions.shape = arc2;
const arc3 = await transforms.rotate(rotateOptions);
rotateOptions.shape = arc3;
const arc4 = await transforms.rotate(rotateOptions);
// Combine all arc edges into a single wire
const combineOptions = new ShapesDto<TopoDSEdgePointer>();
combineOptions.shapes = [arc1, arc2, arc3, arc4];
const combinedWire = await wire.combineEdgesAndWiresIntoAWire(combineOptions);
// Draw the combined wire
bitbybit.draw.drawAnyAsync({ entity: combinedWire });
}
// Execute the function
start();



