Frames
A frame is a point with three axes at right angles. It answers two questions at once: where something sits, and which way it faces. bitbybit.frame builds frames, moves and turns them, lays them out in patterns, and converts points and vectors between a frame and the world.
A frame is plain data, written as three values:
origin: the point the axes start from;normal: where its Z axis points, the way the frame faces;direction: where its X axis points.
The Y axis follows from those two. Every function returns a new frame and never changes the one it was given, so a frame can be passed around freely.
Where frames are used
Frames are how the rest of the API places things:
bitbybit.occt.transforms.placeOnFramesputs a copy of a shape on every frame of a list, andorientmoves a shape from one frame to another. See Transforms.bitbybit.occt.features.holesand its counterbored and countersunk forms drill one hole at each frame: the origin is where the hole enters and the normal points out of the material. See Features.bitbybit.occt.operations.sliceByFramescuts a solid with the plane of each frame. See Sections and slices.bitbybit.occt.analysis.measure.boundingBoxInFramemeasures a shape in a frame of your own.
A shape placed on a frame is moved so that its own X, Y and Z axes lie along the frame's direction, Y axis and normal. A cylinder built along Z therefore stands along each frame's normal.
Building a frame
createtakes all three values. The direction only has to be roughly right: it is turned square to the normal, and both are scaled to length 1.fromPointAndNormaltakes a point and a normal and picks the X axis by a fixed rule, for when only the facing matters.fromThreePointstakes where the frame sits, a point its X axis runs toward and a point on the side its Y axis points to.bestFitfits a frame to points that lie on or near one plane.world,xy,yzandzxgive the frames of the world planes. With Y up,zxis the ground.fromMatrixreads the frame a transformation puts the world frame on, andtoMatrixgoes the other way.
Patterns of frames
grid, hexGrid and polar lay out frames in a frame's plane: a rectangular grid, a honeycomb with one frame at each hexagon's centre, and a ring around the frame's normal. The plane can be tilted any way, and the frames follow it.
Here a frame is tilted off the ground, a grid of frames is laid out in its plane, and one post is placed on every frame. The post is a cylinder built along Z, so each one stands along the tilted normal:
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"tilted": {
"id": "tilted",
"name": "bitbybit.frame.create",
"customName": "frame",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"origin": [
0,
0,
0
],
"normal": [
0,
1,
-0.6
],
"direction": [
1,
0,
0
]
},
"inputs": {},
"position": [
40,
40
]
},
"grid": {
"id": "grid",
"name": "bitbybit.frame.grid",
"customName": "grid",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"countX": 6,
"countY": 4,
"spacingX": 1.5,
"spacingY": 1.5,
"centered": true
},
"inputs": {
"frame": {
"connections": [
{
"node": "tilted",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"post": {
"id": "post",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.25,
"height": 1.5,
"center": [
0,
0,
0
],
"direction": [
0,
0,
1
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
460,
520
]
},
"place": {
"id": "place",
"name": "bitbybit.occt.transforms.placeOnFrames",
"customName": "place on frames",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "post",
"output": "result",
"data": {}
}
]
},
"frames": {
"connections": [
{
"node": "grid",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
}
},
"modules": {}
}
<xml xmlns="https://developers.google.com/blockly/xml"><block type="bitbybit.draw.drawAnyAsyncNoReturn" x="40" y="40"><value name="Entity"><block type="bitbybit.occt.transforms.placeOnFrames"><value name="Shape"><block type="bitbybit.occt.shapes.solid.createCylinder"><value name="Radius"><block type="math_number"><field name="NUM">0.25</field></block></value><value name="Height"><block type="math_number"><field name="NUM">1.5</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">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">1</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="Frames"><block type="bitbybit.frame.grid"><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">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Normal"><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.6</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">0</field></block></value></block></value></block></value><value name="CountX"><block type="math_number"><field name="NUM">6</field></block></value><value name="CountY"><block type="math_number"><field name="NUM">4</field></block></value><value name="SpacingX"><block type="math_number"><field name="NUM">1.5</field></block></value><value name="SpacingY"><block type="math_number"><field name="NUM">1.5</field></block></value><value name="Centered"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value></block></value></block></value></block></xml>
const tilted = bitbybit.frame.create({ origin: [0, 0, 0], normal: [0, 1, -0.6], direction: [1, 0, 0] });
const grid = bitbybit.frame.grid({ frame: tilted, countX: 6, countY: 4, spacingX: 1.5, spacingY: 1.5, centered: true });
const post = await bitbybit.occt.shapes.solid.createCylinder({ radius: 0.25, height: 1.5, center: [0, 0, 0], direction: [0, 0, 1] });
const posts = await bitbybit.occt.transforms.placeOnFrames({ shape: post, frames: grid });
await bitbybit.draw.drawAnyAsync({ entity: posts });
Frames within frames
A frame can be described in another frame's coordinates. frameToWorld places such a frame in the world, and frameToLocal describes a world frame in another frame's terms. The same pairs exist for points (pointToWorld, pointToLocal) and for vectors (vectorToWorld, vectorToLocal), each with a form for lists.
This is how a part is laid out once, around its own origin, and placed anywhere later: draw its holes or its outline in local coordinates, then convert them through the frame where the part goes. matrixFromTo gives the transformation that carries anything placed on one frame onto another.
Moving and turning frames
translate moves a frame by a vector in world coordinates, and offset along its own normal. rotate turns it about one of its own axes, and flip turns it over so its normal points the other way. Each has a form for lists of frames (translateFrames, offsetFrames, rotateFrames, flipFrames).
origin, normal, direction and yDirection read a frame's parts back.
Every function
| Function | What it does |
|---|---|
bestFit | Fits a frame to points that lie on or near one plane. |
create | Builds a frame from where it sits, where its Z axis points and roughly where its X axis points. |
direction | Reads where a frame's X axis points, as a vector of length 1 square to the normal. |
flip | Turns a frame over: its normal points the other way and its Y axis with it, its origin and X axis stay. |
flipFrames | Turns each frame over, as flip turns one: its normal and Y axis point the other way, its origin and X axis stay. |
framesToLocal | Describes frames given in world coordinates in one parent frame's coordinates, the reverse of framesToWorld, as frameToLocal describes one. |
framesToWorld | Places frames given in one parent frame's coordinates into the world, as frameToWorld places one: every child sits on parent as it would sit on the world. |
frameToLocal | Describes a frame given in world coordinates in another frame's coordinates, the reverse of frameToWorld. |
frameToWorld | Places a frame given in another frame's coordinates into the world: a frame within a frame. |
fromMatrix | Reads the frame a transformation puts the world frame on: where it moves the world origin and where it turns the world X and Z axes. |
fromPointAndNormal | Builds a frame from a point and a normal, choosing its X axis by a fixed rule. |
fromThreePoints | Builds a frame from three points: where it sits, a point its X axis runs toward and a point on the side its Y axis points to. |
grid | Lays out a rectangular grid of frames in a frame's plane, each turned the same way as that frame. |
hexGrid | Lays out a honeycomb of frames in a frame's plane, one at each hexagon's center, turned as that frame is. |
matrixFromTo | Gives the transformation that carries anything placed on one frame onto another, turning it the same way. |
normal | Reads where a frame's Z axis points, as a vector of length 1. |
offset | Moves a frame along its own normal, keeping the directions of its axes. |
offsetFrames | Moves each frame along its own normal by the same distance, as offset moves one; their axes keep their directions. |
origin | Reads where a frame sits: the point its three axes start from. |
pointsToLocal | Converts points given in world coordinates into a frame's coordinates, as pointToLocal does for one. |
pointsToWorld | Converts points given in a frame's coordinates into world coordinates, as pointToWorld does for one. |
pointToLocal | Converts a point given in world coordinates into a frame's coordinates, the reverse of pointToWorld. |
pointToWorld | Converts a point given in a frame's coordinates into world coordinates. |
polar | Lays out a ring of frames around a frame's normal, in its plane. |
rotate | Turns a frame about one of its own axes, through its origin. |
rotateFrames | Turns each frame about one of its own axes, through its own origin, as rotate turns one. |
toMatrix | Gives the transformation that moves anything from the world frame onto a frame. |
translate | Moves a frame by a vector in world coordinates, keeping the directions of its axes. |
translateFrames | Moves frames by one vector in world coordinates, as translate moves one; their axes keep their directions. |
vectorToLocal | Turns a vector given along the world axes into one along a frame's axes, the reverse of vectorToWorld. |
vectorToWorld | Turns a vector given along a frame's axes into one along the world axes; the frame's origin plays no part. |
world | Gives the world frame: its origin at zero, its X, Y and Z axes along the world's. |
xy | Builds a frame lying in the XY plane: its X axis along the world X, its Y axis along the world Y and its normal along the world Z. |
yDirection | Reads where a frame's Y axis points: the normal crossed with the direction, as a vector of length 1. |
yz | Builds a frame lying in the YZ plane: its X axis along the world Y, its Y axis along the world Z and its normal along the world X. |
zx | Builds a frame lying in the ZX plane, the ground when Y points up: its X axis along the world Z, its Y axis along the world X and its normal along the world Y. |



