Skip to content

Geometry

Lengths are meters, areas square meters and angles radians, whatever unit the document displays. modlumi.mm(), modlumi.inches() and their inverses convert other units:

const { inches, mm, toMm } = modlumi;
console.log(mm(1000)); // 1
console.log(inches(12)); // about 0.3048
console.log(toMm(0.25)); // 250

Point3d, Vector3d and Transformation are immutable values. Wherever the API takes a point or vector, an [x, y, z] array works too.

const { Point3d, Vector3d } = modlumi;
const a = new Point3d(0, 0, 0);
const b = new Point3d(3, 4, 0);
const offset = a.vectorTo(b); // Vector3d
console.log(offset.length); // 5
console.log(a.offset(new Vector3d(0, 0, 1)).toArray()); // [0, 0, 1]
console.log(a.distance([0, 0, 2])); // 2

entities.addEdges(points) draws connected segments through two or more points. New segments split existing edges where they cross, and closing a planar outline creates a face automatically:

const model = modlumi.activeModel;
const edges = model.operation("Rectangle", () =>
model.activeEntities.addEdges([[0, 0, 0], [4, 0, 0], [4, 3, 0], [0, 3, 0], [0, 0, 0]]),
);
const faces = model.activeEntities.ofType("Face");
console.log(edges.length, "edges and", faces.length, "face");

The returned edges are the ones that lie on the segments you asked for, in model order. Splits mean there isn’t always one edge per segment.

face.extrude(distance) does what the Extrude tool does. A positive distance moves along the face’s normal:

const model = modlumi.activeModel;
const cap = model.operation("Box", () => {
model.entities.addEdges([[0, 0, 0], [4, 0, 0], [4, 3, 0], [0, 3, 0], [0, 0, 0]]);
const [face] = model.entities.ofType("Face");
return face.extrude(2);
});
console.log("Top face area:", cap?.area);
  • The result is the cap face. Keep it for further extrusions, because the original face may be replaced.
  • A distance of zero returns the same face and adds nothing to the history.
  • Extruding into a solid until you reach the opposite side cuts a hole and returns null.
  • Concave faces and faces with holes are supported. Going past the first parallel opposite face, or into geometry Extrude doesn’t support, throws ModelError.
  • Extruding a face inside a component changes the shared definition, so every instance changes.

entities.erase(entity) erases one entity. entities.eraseEdges(edges) erases several edges at once and heals the faces around them. Erasing any edge of a curve this way erases the whole curve.

Build a transformation and apply it to elements of one context with transformEntities. Edges that share a vertex stay connected:

const { Transformation } = modlumi;
const model = modlumi.activeModel;
model.operation("Square", () => {
model.activeEntities.addEdges([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 0]]);
});
const elements = model.activeEntities.toArray().filter((e) => e.type !== "Guide");
const move = Transformation.translation([2, 0, 0]);
const turn = Transformation.rotation([2, 0, 0], [0, 0, 1], Math.PI / 4);
model.operation("Move and turn", () => {
model.activeEntities.transformEntities(turn.multiply(move), elements);
});

a.multiply(b) composes two transformations, applying b first. Multiplying a point includes the translation, and multiplying a vector doesn’t. The transformation is in the coordinates of the Entities you call it on.

To move a whole group or component instance, change its placement instead:

  • placement.transform(t) applies t on top of the current placement.
  • placement.transformation = t replaces the placement.

Both work in the parent’s coordinates and leave the shared definition unchanged.

copyEntities copies elements with a transformation and returns the copies. Face boundaries, complete curves and holes come along, groups and instances keep their definitions, and copies don’t merge with geometry they overlap. This makes a radial array of six copies around the Z axis:

const { Transformation } = modlumi;
const model = modlumi.activeModel;
const original = model.operation("Post", () =>
model.activeEntities.addEdges([[3, 0, 0], [3.2, 0, 0], [3.2, 0.2, 0], [3, 0.2, 0], [3, 0, 0]]),
);
const elements = [...original, ...model.activeEntities.ofType("Face")];
const count = 6;
model.operation("Radial array", () => {
for (let i = 1; i < count; i++) {
const angle = (2 * Math.PI * i) / count;
model.activeEntities.copyEntities(Transformation.rotation([0, 0, 0], [0, 0, 1], angle), elements);
}
});