Skip to main content

Polylines in Bitbybit

Polyline category icon

View Full Source & Details on GitHub

bitbybit.polyline works with polylines: chains of straight segments through a list of points. Lengths are in model units.

What a polyline is​

A polyline is an object { points: [[x1,y1,z1], [x2,y2,z2], ...], isClosed }. When isClosed is true, a last segment joins the last point back to the first, so the polyline outlines a polygon. The first point need not be repeated at the end.

create builds one from a list of points and isClosed (default false).

Reading and measuring​

  • getPoints gives the list of points and countPoints counts them.
  • length adds up the distances between neighbouring points. The closing segment of a closed polyline is not counted, so to measure the full loop of a polygon, repeat its first point at the end.
  • polygonArea measures the area the polyline encloses, read as a closed outline whether isClosed is set or not. The result is never negative.
  • polygonNormal gives the unit normal of that outline, pointing the way the outline turns by the right-hand rule: a square traced counter-clockwise in the XY plane gives [0, 0, 1]. It holds for outlines that are not convex or not quite flat, and an outline with no area gives undefined.

Reversing and transforming​

  • reverse reverses the order of the points, so the polyline runs the other way. It reverses the point list of the polyline you pass in, and the polyline it gives has no isClosed; set it again with create when it matters.
  • transformPolyline applies a transformation matrix, or a list of them in order, such as bitbybit.babylon.transforms builds, to every point. The result is a new polyline, also without isClosed.

Splitting into segments​

  • polylineToSegments gives one segment [start, end] per pair of neighbouring points, and polylineToLines gives the same as line objects { start, end }.
  • For a closed polyline both add the segment from the last point back to the first, unless the two points already coincide.

Where polylines cross​

  • polylineSelfIntersection finds the points where a polyline crosses itself. Neighbouring segments, which always share a point, are not tested against each other.
  • twoPolylineIntersection finds the points where two polylines cross, testing every segment of one against every segment of the other.

Both use tolerance (default 1e-5): crossings closer together than it are reported once.

Joining loose segments​

sortSegmentsIntoPolylines takes segments in any order and joins those whose ends meet within tolerance into polylines. A chain that comes back to where it started becomes a closed polyline, without its first point repeated at the end. A segment that touches nothing becomes a polyline of its own. bitbybit.mesh uses it to turn the segments where two meshes cut each other into curves.

Fillets at corners​

  • maxFilletsHalfLine gives the largest fillet radius for every corner, each limited to the nearer half of its two segments so the fillets never overlap. A closed polyline also gets the corners at its first and last points.
  • safestFilletRadius gives the smallest of those: one radius that fits every corner. A polyline with fewer than three points, or any corner that allows no fillet, gives 0.

The same calculations for loose points are in bitbybit.point.

Here the corners of an OpenCascade star are read into a closed polyline. safestFilletRadius finds the largest radius every corner allows, and the star is rounded with it:

Bitbybit Platform

The largest fillet a star allows in Rete

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"star": {
"id": "star",
"name": "bitbybit.occt.shapes.wire.createStarWire",
"customName": "star wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"numRays": 7,
"outerRadius": 6,
"innerRadius": 3,
"offsetOuterEdges": 0,
"half": false
},
"inputs": {},
"position": [
40,
40
]
},
"corners": {
"id": "corners",
"name": "bitbybit.occt.shapes.wire.divideWireByEqualDistanceToPoints",
"customName": "divide wire by equal distance to points",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"nrOfDivisions": 14,
"removeStartPoint": false,
"removeEndPoint": true
},
"inputs": {
"shape": {
"connections": [
{
"node": "star",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"outline": {
"id": "outline",
"name": "bitbybit.polyline.create",
"customName": "polyline",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"isClosed": true
},
"inputs": {
"points": {
"connections": [
{
"node": "corners",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"radius": {
"id": "radius",
"name": "bitbybit.polyline.safestFilletRadius",
"customName": "safest fillet radius",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"tolerance": 0.00001
},
"inputs": {
"polyline": {
"connections": [
{
"node": "outline",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"rounded": {
"id": "rounded",
"name": "bitbybit.occt.fillets.fillet2d",
"customName": "fillet 2d",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.1
},
"inputs": {
"shape": {
"connections": [
{
"node": "star",
"output": "result",
"data": {}
}
]
},
"radius": {
"connections": [
{
"node": "radius",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
}
},
"modules": {}
}

Every function​

FunctionWhat it does
countPointsCounts the points of the polyline.
createBuilds a polyline object from points, open or closed.
getPointsReads the list of points out of the polyline.
lengthMeasures the polyline by adding up the straight distances between neighboring points.
maxFilletsHalfLineFinds the largest fillet for every corner of the polyline, each limited to the nearer half of its segments so the fillets never overlap.
polygonAreaMeasures the area a polyline encloses, read as a closed outline in its own plane.
polygonNormalFinds the unit normal of the plane a polyline encloses, read as a closed outline.
polylineSelfIntersectionFinds the points where the polyline crosses itself.
polylineToLinesSplits the polyline into line objects, one per segment, each with a start and an end point.
polylineToSegmentsSplits the polyline into segments, each a pair of points.
reverseReverses the order of the points, so the polyline runs the other way.
safestFilletRadiusFinds one fillet radius that fits every corner of the polyline: the smallest of the per-corner maximums under the half-segment rule.
sortSegmentsIntoPolylinesJoins loose segments into polylines by matching up ends that meet within the tolerance.
transformPolylineApplies a transformation matrix, or a list of them in order, to every point of the polyline.
twoPolylineIntersectionFinds the points where two polylines cross each other, testing every segment of one against every segment of the other.