@huukhanhnguyen/types / objects/brep
objects/brep
BrepData
BrepData = {
edges:BrepEdge[];faces:BrepFace[];loops:BrepLoop[];vertices:BrepVertex[]; }
Shared topology tables of one body. The geometry may contain several topological shells' faces; the partition is derived (classifyShells). Same stem as the BrepData ops namespace.
edges
edges:
BrepEdge[]
faces
faces:
BrepFace[]
loops
loops:
BrepLoop[]
vertices
vertices:
BrepVertex[]
BrepEdge
BrepEdge = {
attributes?:Record<string,unknown>;curve:Segment;end:number;start:number;tolerance?:number; }
A curve bounded by two vertices, given as indices into the document's vertex table. The parameter window is the carrier's own natural range.
attributes?
optionalattributes?:Record<string,unknown>
curve
curve:
Segment
end
end:
number
start
start:
number
tolerance?
optionaltolerance?:number
BrepFace
BrepFace = {
attributes?:Record<string,unknown>;innerLoops:number[];layer?:string;material?:string;outerLoop:number;reversed:boolean;surface:Surface;tolerance?:number;uvCurves:BrepFaceUvCurve[];uvMatrix?:Transformation; }
A bounded patch of a surface: one outer loop, plus inner loops that cut holes.
The geometry kernel derives the chart window from surface + outer trim (Store::natural_bounds).
reversed — whether the face's outward normal opposes its surface's natural normal. Surfaces are shared via Rc across faces, so orientation cannot be folded into the carrier.
uvCurves — one PolyCurve2d per boundary edge. Seam-unwrap anchors are baked into that chain on write.
A seam edge is walked TWICE by one loop, once per parameter column, and the second image is not stored: the kernel computes it by translating the first one period along the periodic direction (Store::uv_curve_on_use).
attributes?
optionalattributes?:Record<string,unknown>
innerLoops
innerLoops:
number[]
layer?
optionallayer?:string
Layer key for THIS face, overriding its placement's Instance.layer. Absent === inherit from the instance.
Per-face for the reason material already is: an IMPORTED document can carry N different layers across its faces before it is ever wrapped into one Object — DXF especially, which assigns layer per ENTITY and never per block — and collapsing that to one Instance-level layer on arrival loses what the file actually said.
material?
optionalmaterial?:string
Material key for THIS face, overriding its placement's Instance.material. Absent === inherit from the instance.
The oldest per-face lane reference and the reason layer is one too: a boolean fragment, an OBJ usemtl run or a glTF primitive names a material per FACE, and one document holds many faces, so the claim cannot ride the placement.
outerLoop
outerLoop:
number
reversed
reversed:
boolean
surface
surface:
Surface
tolerance?
optionaltolerance?:number
Surface-fit tolerance; omitted when at the 1e-7 default.
uvCurves
uvCurves:
BrepFaceUvCurve[]
uvMatrix?
optionaluvMatrix?:Transformation
Authored row-major 4×4 plane→world UV frame for THIS face (world = uvMatrix · [u,v,0,1]). Absent ⇒ derived from the face's own surface on read. Per-face, never per-shell.
BrepFaceUvCurve
BrepFaceUvCurve = {
edge:number;uvCurve:PolyCurve2d; }
A uv image recorded on a face for one of its boundary edges: one PolyCurve2d in the face's (u, v). Reverse, a partial window and a 3D-projected image are baked into that chain on write.
edge
edge:
number
uvCurve
uvCurve:
PolyCurve2d
BrepInstance
BrepInstance =
BaseInstance& {material?:string; }
BrepLoop
BrepLoop = {
orientedEdges:OrientedEdge[]; }
An ordered, closed chain of oriented edges bounding a region of a face.
No type parameter, no tolerance, no attributes: a loop carries no geometry, only the order its edges are walked in.
It does NOT say whether it is the outer boundary or a hole — the FACE declares which of its loops is outer. OpenNURBS carries the claim on both, where they can disagree; one source cannot.
orientedEdges
orientedEdges:
OrientedEdge[]
BrepObject
BrepObject =
BaseObject& {data:BrepData;instances:BrepInstance[];type:"brep"; }
An object whose data is one kernel brep — one body.
A boolean that returns a body with cavities stays one object; the shell partition is derived inside the kernel.
BrepVertex
BrepVertex = {
attributes?:Record<string,unknown>;position:Point;tolerance?:number; }
A point in the topology, plus the ball inside which two coincident vertices are the same vertex.
tolerance ABSENT means 0 means EXACT — the convention every optional tolerance in this package keeps, so the lean document is also the exact one.
KNOWN GAP: no producer in this repo satisfies that convention yet. Measured 2026-08-09 across brep_cylinder, brep_sphere, brep_box and box − cylinder: every vertex and every edge carries the same stamped constant 1e-7, and nothing carries 0. So "exact" is an empty category today, and tolerance cannot be used to tell an exact element from a fitted one — a rule of the form "do X only when tolerance > 0" fires on everything. The convention above states the INTENT; treat a 1e-7 you read as "unset", not as a measured deviation. This matters beyond bookkeeping: BrepVertex.tolerance is read both as an identity ball and as a closure band, and a stamped constant makes those bands identical regardless of how the point was produced.
attributes?
optionalattributes?:Record<string,unknown>
position
position:
Point
tolerance?
optionaltolerance?:number
OrientedEdge
OrientedEdge = {
edge:number;forward:boolean; }
An edge taken in a traversal direction. forward walks start → end.
edge
edge:
number
forward
forward:
boolean
Surface
Surface = {
type:"plane"; } &PlaneSurface| {type:"revolve"; } &RevolveSurface| {formAbsent?:boolean;type:"nurbs";uPeriodic?:boolean;vPeriodic?:boolean; } &NurbsSurface
The document's surface carrier: the three kinds of the PlaneSurface / RevolveSurface / NurbsSurface union (geometry/surface.ts) wearing their type tags, plus carrier-only fields on the nurbs arm that are document concerns rather than geometry.