Pin with Label
Pin with label is a powerful annotation tool that creates visual markers with text labels to highlight important points, display calculated values, or provide contextual information in your 3D models. These pins consist of a line connecting two points with customizable text labels, making them perfect for technical documentation, design reviews, and educational materials.
Understanding Pin with Label
Pin with label annotations combine geometric positioning with text information to create clear, professional annotations. They're essential for communicating design intent, displaying calculated properties, and marking critical features in your models.
Key components include:
- Start Point: The point where the pin originates (usually on or near your geometry)
- End Point: The point where the pin terminates (typically positioned for optimal label visibility)
- Direction Vector: Controls the orientation of the label text
- Label Text: The information to display (can be static text or dynamic calculated values)
- Label Positioning: Offset and size controls for optimal readability
Simple Pin with Static Label
The most basic use case is creating a pin with static text to mark important points in your model.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"a1b2c3d4e5f6g7h8": {
"id": "a1b2c3d4e5f6g7h8",
"name": "bitbybit.point.pointXYZ",
"customName": "start point",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {},
"position": [
-3.082380360351779,
4.874850306260413
]
},
"b2c3d4e5f6g7h8i9": {
"id": "b2c3d4e5f6g7h8i9",
"name": "bitbybit.point.pointXYZ",
"customName": "end point",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 3,
"y": 2,
"z": 1
},
"inputs": {},
"position": [
-3.8143436709497607,
356.9627885959876
]
},
"c3d4e5f6g7h8i9j0": {
"id": "c3d4e5f6g7h8i9j0",
"name": "bitbybit.vector.vectorXYZ",
"customName": "direction",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 1,
"y": 0,
"z": 0
},
"inputs": {},
"position": [
-8.496903479843652,
707.145616899227
]
},
"d4e5f6g7h8i9j0k1": {
"id": "d4e5f6g7h8i9j0k1",
"name": "bitbybit.occt.dimensions.pinWithLabel",
"customName": "pin with label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"startPoint": [
0,
0,
0
],
"endPoint": [
0,
5,
2
],
"direction": [
0,
0,
1
],
"offsetFromStart": 0,
"label": "Important Point",
"labelOffset": 0.3,
"labelSize": 0.4
},
"inputs": {
"startPoint": {
"connections": [
{
"node": "a1b2c3d4e5f6g7h8",
"output": "result",
"data": {}
}
]
},
"endPoint": {
"connections": [
{
"node": "b2c3d4e5f6g7h8i9",
"output": "result",
"data": {}
}
]
},
"direction": {
"connections": [
{
"node": "c3d4e5f6g7h8i9j0",
"output": "result",
"data": {}
}
]
}
},
"position": [
567.8101091255851,
313.38590437874376
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="fgeiUoQm$kRn0loAmyRM" x="-173" y="-13"><value name="Entity"><block type="bitbybit.occt.dimensions.pinWithLabel" id="yKrU^[e1O|Tox2ddsQ$U"><value name="StartPoint"><block type="bitbybit.point.pointXYZ" id="3e?$A5f$qI}@h@c]k8~j"><value name="X"><block type="math_number" id=".g#F4vOTD8[}Z$)t`dN}"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="pu$Hq4oIO_A_V)+io4I~"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="BVwnig`6WRyvDx_q~IgO"><field name="NUM">0</field></block></value></block></value><value name="EndPoint"><block type="bitbybit.point.pointXYZ" id="JQ#jG,fBtEsy:`pC=.KH"><value name="X"><block type="math_number" id="}m~jsS`1+Eg;YL!W4]2n"><field name="NUM">3</field></block></value><value name="Y"><block type="math_number" id="ry85@gKPTl*lE4gL|WW|"><field name="NUM">2</field></block></value><value name="Z"><block type="math_number" id="T~5flBYN6xx~1X8]O]~7"><field name="NUM">1</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="^UQBTw97.rgI^Bi7/RJ0"><value name="X"><block type="math_number" id="GsHt^J$/TVIORKEv-@3V"><field name="NUM">1</field></block></value><value name="Y"><block type="math_number" id="_FIWm4sXHc7#;:1P$00N"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="#Va^Vt36uVNaOUXRzb09"><field name="NUM">0</field></block></value></block></value><value name="OffsetFromStart"><block type="math_number" id="kc62+1=8KXU1zH8._DHO"><field name="NUM">0</field></block></value><value name="Label"><block type="text" id="Ibuvumx#6;Qhb7U@I5Ci"><field name="TEXT">Important Point</field></block></value><value name="LabelOffset"><block type="math_number" id="4TX?erJklt/33j}k4-Yi"><field name="NUM">0.3</field></block></value><value name="LabelSize"><block type="math_number" id="!6XMA7fSVQFsrbWk9oyS"><field name="NUM">0.4</field></block></value></block></value></block></xml>
// Import the required DTO for pin with label
const { PinWithLabelDto } = Bit.Inputs.OCCT;
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
// Define the main function
const start = async () => {
// Define points for the pin
const startPoint: Point3 = [0, 0, 0];
const endPoint: Point3 = [3, 2, 1];
const direction: Vector3 = [1, 0, 0];
// Create pin with label options
const pinOptions = new PinWithLabelDto();
pinOptions.startPoint = startPoint;
pinOptions.endPoint = endPoint;
pinOptions.direction = direction;
pinOptions.offsetFromStart = 0;
pinOptions.label = "Important Point";
pinOptions.labelOffset = 0.3;
pinOptions.labelSize = 0.4;
// Create and draw the pin
const pin = await bitbybit.occt.dimensions.pinWithLabel(pinOptions);
bitbybit.draw.drawAnyAsync({ entity: pin });
}
// Execute the function
start();
This basic example demonstrates the essential components of a pin with label:
- Start Point at origin
[0, 0, 0]- where the pin begins - End Point at
[3, 2, 1]- where the pin terminates and the label appears - Direction Vector
[1, 0, 0]- controls label text orientation (pointing along X-axis) - Static Label text "Important Point" - simple text annotation
- Label positioning with 0.3 offset and 0.4 size for good readability
Pin with Calculated Properties
A more practical application combines pin labels with calculated geometric properties, similar to how technical drawings display measurements and specifications.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"c66568678586089d": {
"id": "c66568678586089d",
"name": "bitbybit.math.numberSlider",
"customName": "radius",
"data": {
"options": {
"min": 1,
"max": 5,
"step": 0.1,
"width": 300,
"updateOnDrag": true
},
"number": 2.5
},
"inputs": {},
"position": [
42.37234172395962,
107.44633517914559
]
},
"b2c3d4e5f6g7h8i9": {
"id": "b2c3d4e5f6g7h8i9",
"name": "bitbybit.occt.shapes.solid.createSphere",
"customName": "sphere",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 2.5,
"center": [
0,
0,
0
]
},
"inputs": {
"radius": {
"connections": [
{
"node": "c66568678586089d",
"output": "result",
"data": {}
}
]
}
},
"position": [
1028.4532554896928,
63.44938865666802
]
},
"c3d4e5f6g7h8i9j0": {
"id": "c3d4e5f6g7h8i9j0",
"name": "bitbybit.occt.shapes.solid.getSolidVolume",
"customName": "get volume",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "b2c3d4e5f6g7h8i9",
"output": "result",
"data": {}
}
]
}
},
"position": [
1424.1082301913739,
60.27055877703206
]
},
"d4e5f6g7h8i9j0k1": {
"id": "d4e5f6g7h8i9j0k1",
"name": "bitbybit.math.roundToDecimals",
"customName": "round volume",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 1.123456,
"decimalPlaces": 2
},
"inputs": {
"number": {
"connections": [
{
"node": "c3d4e5f6g7h8i9j0",
"output": "result",
"data": {}
}
]
}
},
"position": [
1797.4006197699327,
61.31067901531682
]
},
"e5f6g7h8i9j0k1l2": {
"id": "e5f6g7h8i9j0k1l2",
"name": "bitbybit.text.format",
"customName": "format volume",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "Vol: {0} m3",
"values": [
"World"
]
},
"inputs": {
"values": {
"connections": [
{
"node": "aed40f273ec67645",
"output": "list",
"data": {}
}
]
}
},
"position": [
2924.572795632677,
19.910741652073355
]
},
"aed40f273ec67645": {
"id": "aed40f273ec67645",
"name": "bitbybit.lists.createList",
"customName": "volume list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "g7h8i9j0k1l2m3n4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2546.460084525186,
96.60716110138223
]
},
"g7h8i9j0k1l2m3n4": {
"id": "g7h8i9j0k1l2m3n4",
"name": "bitbybit.text.toString",
"customName": "volume to string",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"item": {
"connections": [
{
"node": "d4e5f6g7h8i9j0k1",
"output": "result",
"data": {}
}
]
}
},
"position": [
2170.95886498554,
58.543647593272425
]
},
"h8i9j0k1l2m3n4o5": {
"id": "h8i9j0k1l2m3n4o5",
"name": "bitbybit.point.pointXYZ",
"customName": "pin start",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"z": {
"connections": [
{
"node": "c66568678586089d",
"output": "result",
"data": {}
}
]
}
},
"position": [
1810.5462022760823,
-1193.3432054975422
]
},
"i9j0k1l2m3n4o5p6": {
"id": "i9j0k1l2m3n4o5p6",
"name": "bitbybit.point.pointXYZ",
"customName": "pin end",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 4,
"y": 3,
"z": 0
},
"inputs": {
"z": {
"connections": [
{
"node": "j0k1l2m3n4o5p6q7",
"output": "result",
"data": {}
}
]
}
},
"position": [
2196.4694618686303,
-808.0481131190422
]
},
"j0k1l2m3n4o5p6q7": {
"id": "j0k1l2m3n4o5p6q7",
"name": "bitbybit.math.add",
"customName": "pin height",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2
},
"inputs": {
"first": {
"connections": [
{
"node": "c66568678586089d",
"output": "result",
"data": {}
}
]
}
},
"position": [
1794.5859002094235,
-731.4406370552683
]
},
"k1l2m3n4o5p6q7r8": {
"id": "k1l2m3n4o5p6q7r8",
"name": "bitbybit.vector.vectorXYZ",
"customName": "direction",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 1,
"y": 0,
"z": 0
},
"inputs": {},
"position": [
2197.6871669225566,
-433.8215024712347
]
},
"l2m3n4o5p6q7r8s9": {
"id": "l2m3n4o5p6q7r8s9",
"name": "bitbybit.occt.dimensions.pinWithLabel",
"customName": "volume pin",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"startPoint": [
0,
0,
0
],
"endPoint": [
0,
5,
2
],
"direction": [
0,
0,
1
],
"offsetFromStart": 0,
"label": "Volume Pin",
"labelOffset": 0.3,
"labelSize": 0.4
},
"inputs": {
"startPoint": {
"connections": [
{
"node": "h8i9j0k1l2m3n4o5",
"output": "result",
"data": {}
}
]
},
"endPoint": {
"connections": [
{
"node": "i9j0k1l2m3n4o5p6",
"output": "result",
"data": {}
}
]
},
"direction": {
"connections": [
{
"node": "k1l2m3n4o5p6q7r8",
"output": "result",
"data": {}
}
]
},
"label": {
"connections": [
{
"node": "e5f6g7h8i9j0k1l2",
"output": "result",
"data": {}
}
]
}
},
"position": [
3518.309591588108,
-857.7165027776839
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="tFn{#Jp(U~%-tJ!jYFZe">radius</variable><variable id="xc]EktUoaR-Gm0~E;+JK">sphere</variable><variable id="aIYE0t6:W~X:n-Uj41=f">volume</variable></variables><block type="variables_set" id="3-{|Jxy8)ff37;yS;c^4" x="-157" y="-286"><field name="VAR" id="tFn{#Jp(U~%-tJ!jYFZe">radius</field><value name="VALUE"><block type="math_number" id="Vl3AUHk0gg4]B2pUc*PO"><field name="NUM">2.5</field></block></value><next><block type="variables_set" id="[a9;`1j4o2`_Wr1:VUT~"><field name="VAR" id="xc]EktUoaR-Gm0~E;+JK">sphere</field><value name="VALUE"><block type="bitbybit.occt.shapes.solid.createSphere" id="3(X0PcxYrC?dHx{c%}$f"><value name="Radius"><block type="variables_get" id="%LMtIi*:Q69`3Fve1Iuy"><field name="VAR" id="tFn{#Jp(U~%-tJ!jYFZe">radius</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ" id="OLLcb3;WluvT`Fl7FiFB"><value name="X"><block type="math_number" id="@8A=M=xG(9R]A+Y5$)a/"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="nDVoC8aSKs66D@]G`]]w"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="HNPo=~#Ys?C{LB/WyoHc"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="fEC/Idzc)hC0qQ7dZCD="><field name="VAR" id="aIYE0t6:W~X:n-Uj41=f">volume</field><value name="VALUE"><block type="base_time_await_return" id="kKly_|;T[E$TBTr,vH$h"><value name="Promise"><block type="bitbybit.occt.shapes.solid.getSolidVolume" id="m`eTR3Y(r#NIZg{~PqS-"><value name="Shape"><block type="variables_get" id="[4^~C+gu,/m?LXsDcGNf"><field name="VAR" id="xc]EktUoaR-Gm0~E;+JK">sphere</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="~DNH%2A?1Of$JLQm5{R."><value name="Entity"><block type="bitbybit.occt.dimensions.pinWithLabel" id="hBnh=5=rU3P`VysPD(N;"><value name="StartPoint"><block type="bitbybit.point.pointXYZ" id="T4j~oRr8rp@M%COyy7p9"><value name="X"><block type="math_number" id="_zit%eN[O)eE_et:YJk9"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="WP^rod.Y[Y]E)o-4owoe"><field name="NUM">0</field></block></value><value name="Z"><block type="variables_get" id="fBPv}k[jLE0f^4~Q^vFq"><field name="VAR" id="tFn{#Jp(U~%-tJ!jYFZe">radius</field></block></value></block></value><value name="EndPoint"><block type="bitbybit.point.pointXYZ" id="EEexWc7wq+J2pYdq_z6U"><value name="X"><block type="math_number" id="]-|M~[g!6o;$^]D@?oKt"><field name="NUM">4</field></block></value><value name="Y"><block type="math_number" id="n3nb}0:iG17hn4wd,!h$"><field name="NUM">3</field></block></value><value name="Z"><block type="math_arithmetic" id="zdZ3YI)~+IuF+3kKK?e!"><field name="OP">ADD</field><value name="A"><block type="variables_get" id="2gDkrQ-eSE@4sJShk!wK"><field name="VAR" id="tFn{#Jp(U~%-tJ!jYFZe">radius</field></block></value><value name="B"><block type="math_number" id="5pt{6H^0yd1?GQ[j%lLi"><field name="NUM">2</field></block></value></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="^W.S_*6BL~-4R(P.E5R?"><value name="X"><block type="math_number" id="$}5fHVxcmzU,HkzKCl*j"><field name="NUM">1</field></block></value><value name="Y"><block type="math_number" id="3bmF++IE7+be[X:72L[?"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id=";j`Vw)*|{M/kk{2|i|x0"><field name="NUM">0</field></block></value></block></value><value name="OffsetFromStart"><block type="math_number" id="cr.}c(J7s2Rh#{#.X}L!"><field name="NUM">0</field></block></value><value name="Label"><block type="bitbybit.text.format" id="DCU_$N_JdE|nU.^i1toH"><value name="Text"><block type="text" id="x}|)-oHP,)8$+aY*286y"><field name="TEXT">Vol: {0} m3</field></block></value><value name="Values"><block type="lists_create_with" id="*Vw?9UJGDNj_iJfI3*i7"><mutation items="1"></mutation><value name="ADD0"><block type="bitbybit.math.roundToDecimals" id="0^jHNm#,#Zw/5O+V8ft3"><value name="Number"><block type="variables_get" id="iI*d_r#f_clI])~Fc*41"><field name="VAR" id="aIYE0t6:W~X:n-Uj41=f">volume</field></block></value><value name="DecimalPlaces"><block type="math_number" id="9~uQ?dN?kOuwGK#t^w0~"><field name="NUM">2</field></block></value></block></value></block></value></block></value><value name="LabelOffset"><block type="math_number" id="hyTt68s,2.yZO3`b*L:K"><field name="NUM">0.3</field></block></value><value name="LabelSize"><block type="math_number" id="p,7@2g-HHDji*qoZeax|"><field name="NUM">0.4</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="Mt?I$7qJb8S`wet%`EL#"><value name="Entity"><block type="variables_get" id="E:mSruxRtX%YmPgUObe$"><field name="VAR" id="xc]EktUoaR-Gm0~E;+JK">sphere</field></block></value></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs and types
const { SphereDto, PinWithLabelDto } = Bit.Inputs.OCCT;
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
// Get access to OCCT modules
const { solid } = bitbybit.occt.shapes;
const { dimensions } = bitbybit.occt;
const { math, text } = bitbybit;
// Define the main function
const start = async () => {
// Parametric radius value
const radius = 2.5;
// Create a sphere
const sphereOptions = new SphereDto();
sphereOptions.radius = radius;
sphereOptions.center = [0, 0, 0] as Point3;
const sphere = await solid.createSphere(sphereOptions);
// Calculate sphere volume
const volume = await solid.getSolidVolume({ shape: sphere });
const roundedVolume = math.roundToDecimals({ number: volume, decimalPlaces: 2 });
// Format volume as text with units
const volumeText = text.format({
text: "Vol: {0} m3",
values: [text.toString({ item: roundedVolume })]
});
// Create pin with calculated volume label
const pinOptions = new PinWithLabelDto();
pinOptions.startPoint = [0, 0, radius] as Point3; // Start at top of sphere
pinOptions.endPoint = [4, 3, radius + 2] as Point3; // Position for visibility
pinOptions.direction = [1, 0, 0] as Vector3;
pinOptions.offsetFromStart = 0;
pinOptions.label = volumeText;
pinOptions.labelOffset = 0.3;
pinOptions.labelSize = 0.4;
// Create and draw the pin
const pin = await dimensions.pinWithLabel(pinOptions);
// Draw both sphere and pin
bitbybit.draw.drawAnyAsync({ entity: sphere });
bitbybit.draw.drawAnyAsync({ entity: pin });
}
// Execute the function
start();
This example demonstrates how to combine pin labels with calculated geometric properties:
- Parametric Sphere: Created with a configurable radius (2.5 units)
- Volume Calculation: Uses
getSolidVolumeto compute the sphere's volume - Dynamic Formatting: Rounds volume to 2 decimal places and formats with units ("Vol: 65.45 m³")
- Smart Positioning: Pin starts at the sphere's top surface and extends to a clear viewing position
- Responsive Layout: Pin height adjusts based on sphere radius for consistent visual presentation
This pattern is commonly used in engineering applications where you need to annotate models with calculated properties that update automatically when geometry parameters change.



