@huukhanhnguyen/types / geometry/surface
geometry/surface
NurbsSurface
NurbsSurface = {
controlPoints:Point[][];degreeU:number;degreeV:number;knotsU:number[];knotsV:number[];weights:number[][]; }
controlPoints
controlPoints:
Point[][]
degreeU
degreeU:
number
degreeV
degreeV:
number
knotsU
knotsU:
number[]
knotsV
knotsV:
number[]
weights
weights:
number[][]
PlaneSurface
PlaneSurface = {
d:number;normal:Vector;origin?:Point;uvMax:Point2d;uvMin:Point2d;xAxis?:Vector;yAxis?:Vector; }
A plane, given as its implicit equation plus the finite window it is used over.
d
d:
number
The plane's implicit constant: the surface is normal · p = d.
normal
normal:
Vector
origin?
optionalorigin?:Point
Form origin of the UV frame. Absent on older documents: the loader then uses the foot of the world origin, which is the wrong UV origin for a translated disk.
uvMax
uvMax:
Point2d
Upper-right corner of the finite rectangle in surface UV.
uvMin
uvMin:
Point2d
Lower-left corner of the finite rectangle in surface UV.
xAxis?
optionalxAxis?:Vector
In-plane U axis. Paired with origin / yAxis.
yAxis?
optionalyAxis?:Vector
In-plane V axis. Paired with origin / xAxis.
RevolveSurface
RevolveSurface = {
angle: [number,number];axis:Axis;profile:Segment; }
A profile curve swept about an axis.
u is ALWAYS the ANGLE and v is ALWAYS the profile. The profile owns its own parameter domain.
This is the OPPOSITE of Rhino's ON_RevSurface, which puts the profile on u. Do not "fix" it back after reading that reference — the order here was verified against this kernel rather than imported: a cylinder(2, 5) reports uMin 0, uMax 2π, vMin 0, vMax 5, and a sphere(2) reports uMin 0, uMax 2π, vMin -π/2, vMax π/2. u sweeps, v runs along the profile. Every analytic carrier agrees, and operations/revolve.rs transposes the general construction to match. A face's uv curves live in that exact uv, so swapping the order would silently invalidate every uv curve on every revolve face.
Revolution earns a kind of its own where extrusion does not, and the reason is the parametrization rather than the shape: a linear extrusion's sweep parameter is a distance, which NURBS preserves exactly, so an extrusion is already exactly a NURBS surface and needs no kind. Revolution's sweep parameter is an ANGLE, and NURBS turns an angle into a Möbius reparametrization — so a NURBS carrier holds the same POINTS but no longer the same meaning, and the angle has to be stated to survive.
An arbitrary-profile revolve is EXPRESSIBLE here but only the four NAMED forms are produced — do not read this type as a general capability. Measured 2026-08-09 after the emission pass: surface_to_json writes a revolve entry for any form-tagged cylinder/cone/sphere/torus whose NURBS base is the canonical form layout (the gate is the same agreement check form recovery uses), spelled exactly as the revolveFrom* builders below spell it so the loader's revolve_form folds it back into the same named form — brep_cylinder(2,5) → {"revolve":1,"nurbs":2} (the nurbs entries are the caps' bilinear plane forms), brep_sphere(2) → {"revolve":1}, brep_box(4,4,4) → {"nurbs":6}, box − cylinder → revolve walls plus plane-form nurbs. Two cases keep the NURBS entry: a reparametrized base (an extruded-circle wall), because the rebuilt canonical carrier would move its uv curves' uv, and a form whose (xAxis, yAxis) frame is LEFT-handed about the axis (an opposite-wound hole wall), because the sign carries the winding and a revolve entry cannot state it — the loader always rebuilds yAxis = axis × xAxis. A GENERAL profile (a non-analytic sweep) has no named form to emit from and also crosses as NURBS.
A general-profile emission would need profile recognition at the writer or a general revolve variant on NurbsSurfaceForm, which has only the five NAMED forms — the 182 match arms this fold deliberately left alone.
What the fold DID buy: vRange and xAxis/yAxis stopped being separately stated fields that can disagree with the parametrization — the profile's own extent is the v range and its position is the seam, so that invalid state is now unrepresentable.
angle
angle: [
number,number]
Sweep interval in radians. [0, 2 * Math.PI] is a full turn.
axis
axis:
Axis
The axis swept about — the oriented infinite line of Axis. Reversing direction gives a different axis and therefore the opposite sweep sense, which is exactly what makes an axis able to carry orientation.
profile
profile:
Segment