Surface — Advanced Construction
This page covers the higher-level surface construction APIs: energy-minimising plate and NLPlate surfaces, Bezier and BSpline fills, face-from-surface conversions, constrained geometry factories, and GeomTools persistence. For the core Surface type (properties, analytic primitives, swept surfaces, evaluation), see the main Surface page.
Topics
- Advanced Plate Surfaces · Bezier Surface Fill · BSpline Fill from Boundary Curves · Face from Surface · Constrained Construction, Knot Splitting, Conversions · LocalAnalysis · GeomFill NSections · NLPlate G2/G3, IncrementalSolve, GeomFill_Generator · Extrema, gce Factories, GeomTools Persistence
Advanced Plate Surfaces (v0.23.0)
Surface.plateThrough(_:degree:tolerance:)
Creates a plate surface (parametric BSpline) that passes through a set of unordered 3D points.
public static func plateThrough(
_ points: [SIMD3<Double>],
degree: Int = 3,
tolerance: Double = 0.01
) -> Surface?
Unlike the grid-based fromPointGrid, the points need no ordering or row/column counts — suitable for scattered probe data, feature points, or any unstructured point set. See also the Surfaces from Points cookbook page.
- Parameters:
points— 3D point cloud (minimum 3);degree— maximum polynomial degree;tolerance— approximation tolerance. - Returns: BSpline surface, or
nilif fewer than 3 points orGeomPlate_MakeApproxfails. - OCCT:
GeomPlate_BuildPlateSurface+GeomPlate_PointConstraint+GeomPlate_MakeApprox. - Example:
let points: [SIMD3<Double>] = [ SIMD3(0, 0, 0), SIMD3(10, 0, 1), SIMD3(10, 10, 2), SIMD3(0, 10, 1), SIMD3(5, 5, 3), ] if let plate = Surface.plateThrough(points, degree: 3, tolerance: 0.01) { let face = plate.toFace() }
nlPlateDeformed(constraints:maxIterations:tolerance:)
Deforms this surface to pass through target positions using the non-linear plate solver (NLPlate G0 — position-only constraints).
public func nlPlateDeformed(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>)],
maxIterations: Int = 4,
tolerance: Double = 1e-3
) -> Surface?
Each constraint pins the surface at a (u, v) parameter to a desired 3D location. The solver computes a displacement field on the existing surface; the result preserves the original shape except where pulled by the constraints.
- Parameters:
constraints— array of(uv, target)pairs (non-empty);maxIterations— solver iteration limit;tolerance— approximation tolerance. - Returns: New deformed surface, or
nilif the array is empty or the solver fails. - OCCT:
NLPlate_NLPlate+NLPlate_HPG0Constraint+GeomPlate_MakeApprox. - Example:
let plane = Surface.plane(origin: .zero, normal: SIMD3(0, 0, 1))! if let bumped = plane.nlPlateDeformed( constraints: [(uv: SIMD2(0, 0), target: SIMD3(0, 0, 5))], maxIterations: 4, tolerance: 1e-3 ) { let face = bumped.toFace() } - Note: Distinct from fitting a fresh surface to a point set — the existing parametrisation is preserved.
nlPlateDeformedG1(constraints:maxIterations:tolerance:)
Deforms this surface with position and tangent constraints (NLPlate G0+G1).
public func nlPlateDeformedG1(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>,
tangentU: SIMD3<Double>, tangentV: SIMD3<Double>)],
maxIterations: Int = 4,
tolerance: Double = 1e-3
) -> Surface?
Extends nlPlateDeformed by also constraining the partial derivatives (tangent vectors) in the U and V directions at each constraint point. Use to enforce tangency continuity at the constrained locations.
- Parameters:
constraints— array of(uv, target, tangentU, tangentV)tuples (non-empty);maxIterations— solver iteration limit;tolerance— approximation tolerance. - Returns: New deformed surface, or
nilon failure. - OCCT:
NLPlate_NLPlate+NLPlate_HPG1Constraint+GeomPlate_MakeApprox. - Example:
if let shaped = plane.nlPlateDeformedG1( constraints: [( uv: SIMD2(0.5, 0.5), target: SIMD3(5, 5, 2), tangentU: SIMD3(1, 0, 0), tangentV: SIMD3(0, 1, 0) )], maxIterations: 4, tolerance: 1e-3 ) { let face = shaped.toFace() }
Bezier Surface Fill (v0.31.0)
BezierFillStyle
Filling style for Bezier surface construction from boundary curves.
public enum BezierFillStyle: Int32, Sendable {
case stretch = 0
case coons = 1
case curved = 2
}
stretch— minimal surface area (flattest).coons— bilinear blending between boundaries.curved— smooth curved interpolation (most curved).
Surface.bezierFill(_:_:_:_:style:)
Creates a Bezier surface by filling 4 Bezier boundary curves.
public static func bezierFill(
_ c1: Curve3D, _ c2: Curve3D, _ c3: Curve3D, _ c4: Curve3D,
style: BezierFillStyle = .stretch
) -> Surface?
The four curves must be Bezier curves forming a closed boundary (connected end-to-end in order).
- Parameters:
c1–c4— four Bezier boundary curves in order;style— fill style. - Returns: Bezier surface, or
nilif any curve is not Bezier or the fill fails. - OCCT:
GeomFill_BezierCurves(4-curve constructor). - Example:
// c1..c4 are Bezier curves forming a closed boundary if let surf = Surface.bezierFill(c1, c2, c3, c4, style: .coons) { let face = surf.toFace() }
Surface.bezierFill(_:_:style:)
Creates a Bezier surface by filling 2 Bezier boundary curves as opposite edges.
public static func bezierFill(
_ c1: Curve3D, _ c2: Curve3D,
style: BezierFillStyle = .stretch
) -> Surface?
- Parameters:
c1,c2— two opposing Bezier boundary curves;style— fill style. - Returns: Bezier surface, or
nilon failure. - OCCT:
GeomFill_BezierCurves(2-curve constructor). - Example:
if let surf = Surface.bezierFill(bottom, top, style: .coons) { let face = surf.toFace() }
BSpline Fill from Boundary Curves (v0.43.0)
Surface.FillStyle
Filling style for BSpline surface construction from boundary curves.
public enum FillStyle: Int32, Sendable {
case stretch = 0
case coons = 1
case curved = 2
}
stretch— minimal curvature between boundaries.coons— moderate curvature (Coons-style blending).curved— maximum curvature.
Surface.bsplineFill(curve1:curve2:style:)
Creates a BSpline surface spanning between 2 boundary curves.
public static func bsplineFill(
curve1: Curve3D,
curve2: Curve3D,
style: FillStyle = .coons
) -> Surface?
Both curves must be BSpline (created via Curve3D.bspline or Curve3D.interpolate). The result spans from curve1 to curve2 in the V direction. See also the Gordon Surfaces cookbook for the full fill-vs-Gordon decision guide.
- Parameters:
curve1,curve2— BSpline boundary curves;style— fill style. - Returns: BSpline surface, or
nilif either curve is not BSpline or fill fails. - OCCT:
GeomFill_BSplineCurves(2-curve constructor). - Example:
guard let c1 = Curve3D.interpolate(points: [SIMD3(0,0,0), SIMD3(5,0,2), SIMD3(10,0,0)]), let c2 = Curve3D.interpolate(points: [SIMD3(0,5,0), SIMD3(5,5,3), SIMD3(10,5,0)]) else { return } if let surf = Surface.bsplineFill(curve1: c1, curve2: c2, style: .coons) { let face = surf.toFace() }
Surface.bsplineFill(curves:style:)
Creates a BSpline surface bounded by 4 boundary curves.
public static func bsplineFill(
curves: (Curve3D, Curve3D, Curve3D, Curve3D),
style: FillStyle = .coons
) -> Surface?
The four curves must be BSpline and connected end-to-end in order (bottom, right, top, left).
- Parameters:
curves— four BSpline boundary curves in order;style— fill style. - Returns: BSpline surface, or
nilon failure. - OCCT:
GeomFill_BSplineCurves(4-curve constructor). - Example:
// Four BSpline curves forming a closed loop if let surf = Surface.bsplineFill(curves: (bottom, right, top, left), style: .coons) { let face = surf.toFace() }
Face from Surface (v0.33.0)
toFace(tolerance:)
Creates a face from this surface using its full parameter domain.
public func toFace(tolerance: Double = 1e-6) -> Shape?
Delegates to Shape.face(from:uRange:vRange:tolerance:) with the full domain.uMin...uMax and domain.vMin...vMax ranges. The standard way to convert a parametric Surface to a renderable or sewable Shape.
- Parameters:
tolerance— face creation tolerance. - Returns: Face shape covering the surface’s full UV domain, or
nilon failure. - OCCT:
BRepBuilderAPI_MakeFace(viaShape.face). - Example:
if let surf = Surface.plateThrough(pts), let face = surf.toFace() { let mesh = face.mesh(linearDeflection: 0.1, angularDeflection: 0.3) }
toFace(uRange:vRange:tolerance:)
Creates a face from this surface with specific UV parameter bounds.
public func toFace(
uRange: ClosedRange<Double>,
vRange: ClosedRange<Double>,
tolerance: Double = 1e-6
) -> Shape?
Use to cut out a rectangular UV sub-patch of the surface. For a non-rectangular region, use toFace(uvBoundary:).
- Parameters:
uRange— U parameter range;vRange— V parameter range;tolerance— tolerance. - Returns: Face shape, or
nilon failure. - OCCT:
BRepBuilderAPI_MakeFace(viaShape.face). - Example:
if let face = surf.toFace(uRange: 0.0...0.5, vRange: 0.0...1.0) { // half of the surface in U }
toFace(uvBoundary:)
Creates a face trimmed to a non-rectangular region defined by a closed boundary polygon in UV space.
public func toFace(uvBoundary: [SIMD2<Double>]) -> Shape?
Each segment of the polygon becomes a 2D edge carrying a pcurve on the surface, so the face footprint follows the polygon exactly — unlike toFace(uRange:vRange:), which only makes rectangular UV patches. Ideal for reconstructing a fitted analytic surface trimmed to the real boundary of a region.
- Parameters:
uvBoundary— closed polygon of (u, v) points (minimum 3; the closing segment is implicit). - Returns: The trimmed face, or
nilif fewer than 3 points or construction fails. - OCCT:
OCCTShapeCreateFaceFromSurfaceUVPolygon→BRepBuilderAPI_MakeFacewith pcurve-backed edges. - Example:
// Triangle trimmed from a BSpline surface in UV space let boundary = [SIMD2(0.1, 0.1), SIMD2(0.9, 0.1), SIMD2(0.5, 0.8)] if let face = surf.toFace(uvBoundary: boundary) { let mesh = face.mesh(linearDeflection: 0.1, angularDeflection: 0.3) }
Constrained Geometry Construction, Knot Splitting, Conversions (v0.50.0)
Surface.conicalSurface(origin:direction:semiAngle:radius:)
Creates an infinite conical surface from an axis placement, semi-angle, and base radius.
public static func conicalSurface(
origin: SIMD3<Double> = .zero,
direction: SIMD3<Double> = SIMD3(0, 0, 1),
semiAngle: Double,
radius: Double
) -> Surface?
- Parameters:
origin— apex axis origin;direction— axis direction;semiAngle— half-angle in radians (must be in (0, π/2));radius— base radius at the origin. - Returns: Conical surface, or
nilifsemiAngleis out of range or construction fails. - OCCT:
Geom_ConicalSurfacewithgp_Ax3. - Example:
if let cone = Surface.conicalSurface(semiAngle: .pi / 6, radius: 5) { let face = cone.toFace(uRange: 0...2 * .pi, vRange: 0...20) }
Surface.conicalSurface(point1:point2:r1:r2:)
Creates a conical surface passing through two points with specified radii.
public static func conicalSurface(
point1: SIMD3<Double>,
point2: SIMD3<Double>,
r1: Double,
r2: Double
) -> Surface?
The axis runs from point1 to point2. The cone is defined by radius r1 at point1 and r2 at point2.
- Parameters:
point1— first axis point;point2— second axis point;r1— radius atpoint1;r2— radius atpoint2. - Returns: Conical surface, or
nilon failure. - OCCT:
Geom_ConicalSurfacederived from the two-point-radii geometry. - Example:
if let cone = Surface.conicalSurface( point1: SIMD3(0, 0, 0), point2: SIMD3(0, 0, 10), r1: 5, r2: 2 ) { let face = cone.toFace(uRange: 0...2 * .pi, vRange: 0...10) }
Surface.cylindricalSurface(origin:direction:radius:)
Creates a cylindrical surface from an axis and radius.
public static func cylindricalSurface(
origin: SIMD3<Double> = .zero,
direction: SIMD3<Double> = SIMD3(0, 0, 1),
radius: Double
) -> Surface?
- Parameters:
origin— axis base point;direction— axis direction;radius— cylinder radius. - Returns: Cylindrical surface, or
nilon failure. - OCCT:
Geom_CylindricalSurfacewithgp_Ax3. - Example:
if let cyl = Surface.cylindricalSurface(radius: 5) { let face = cyl.toFace(uRange: 0...2 * .pi, vRange: 0...20) }
Surface.cylindricalSurface(point1:point2:point3:)
Creates a cylindrical surface through three points.
public static func cylindricalSurface(
point1: SIMD3<Double>,
point2: SIMD3<Double>,
point3: SIMD3<Double>
) -> Surface?
The axis passes through point1 and point2; the radius is the distance from point3 to the axis.
- Parameters:
point1— first axis point;point2— second axis point;point3— point defining the radius. - Returns: Cylindrical surface, or
nilon failure. - OCCT:
Geom_CylindricalSurfacefrom the three-point geometry. - Example:
if let cyl = Surface.cylindricalSurface( point1: SIMD3(0, 0, 0), point2: SIMD3(0, 0, 10), point3: SIMD3(5, 0, 0) ) { let face = cyl.toFace(uRange: 0...2 * .pi, vRange: 0...10) }
Surface.planeFromPoints(_:_:_:)
Creates a plane surface through three points.
public static func planeFromPoints(
_ point1: SIMD3<Double>,
_ point2: SIMD3<Double>,
_ point3: SIMD3<Double>
) -> Surface?
- Parameters:
point1,point2,point3— three non-collinear points. - Returns: Plane surface, or
nilif points are collinear. - OCCT:
Geom_Planefromgp_Pln(three-point constructor). - Example:
if let plane = Surface.planeFromPoints( SIMD3(0, 0, 0), SIMD3(10, 0, 0), SIMD3(0, 10, 0) ) { let face = plane.toFace(uRange: 0...10, vRange: 0...10) }
Surface.planeFromPointNormal(point:normal:)
Creates a plane surface from a point and normal direction.
public static func planeFromPointNormal(
point: SIMD3<Double>,
normal: SIMD3<Double>
) -> Surface?
- Parameters:
point— a point on the plane;normal— plane normal direction. - Returns: Plane surface, or
nilon failure. - OCCT:
Geom_Planefromgp_Pln(gp_Pnt, gp_Dir). - Example:
if let plane = Surface.planeFromPointNormal( point: SIMD3(0, 0, 5), normal: SIMD3(0, 0, 1) ) { let face = plane.toFace(uRange: -10...10, vRange: -10...10) }
Surface.trimmedCone(point1:point2:r1:r2:)
Creates a trimmed (bounded) conical surface between two endpoints with specified radii.
public static func trimmedCone(
point1: SIMD3<Double>,
point2: SIMD3<Double>,
r1: Double,
r2: Double
) -> Surface?
Unlike conicalSurface, the result is a Geom_RectangularTrimmedSurface already bounded to the axial extent between point1 and point2.
- Parameters:
point1— base centre (with radiusr1);point2— top centre (with radiusr2);r1,r2— respective radii. - Returns: Bounded trimmed conical surface, or
nilon failure. - OCCT:
GC_MakeTrimmedCone. - Example:
if let cone = Surface.trimmedCone( point1: SIMD3(0, 0, 0), point2: SIMD3(0, 0, 10), r1: 5, r2: 2 ) { let face = cone.toFace() }
Surface.trimmedCylinder(origin:direction:radius:height:)
Creates a trimmed (bounded) cylindrical surface from axis, radius, and height.
public static func trimmedCylinder(
origin: SIMD3<Double> = .zero,
direction: SIMD3<Double> = SIMD3(0, 0, 1),
radius: Double,
height: Double
) -> Surface?
- Parameters:
origin— base centre;direction— axis direction;radius— cylinder radius;height— axial height (negative = downward). - Returns: Bounded trimmed cylindrical surface, or
nilon failure. - OCCT:
GC_MakeTrimmedCylinder. - Example:
if let cyl = Surface.trimmedCylinder(radius: 5, height: 20) { let face = cyl.toFace() }
knotSplitting(uContinuity:vContinuity:)
Analyses where a BSpline surface would need to be split to achieve a given continuity level.
public func knotSplitting(uContinuity: Int = 1, vContinuity: Int = 1) -> KnotSplitResult
Returns the number of U and V splits needed; does not modify the surface.
- Parameters:
uContinuity— desired U continuity (0=C0, 1=C1, 2=C2);vContinuity— desired V continuity. - Returns:
KnotSplitResultwithuSplitCountandvSplitCount. - OCCT:
BSplSLib::KnotSplitting. - Example:
let result = surf.knotSplitting(uContinuity: 2, vContinuity: 2) print("U splits needed:", result.uSplitCount) print("V splits needed:", result.vSplitCount)
Surface.joinBezierPatches(_:rows:cols:)
Joins a rectangular grid of Bezier surface patches into a single BSpline surface.
public static func joinBezierPatches(
_ patches: [Surface],
rows: Int,
cols: Int
) -> Surface?
Adjacent patches must share boundary curves. The patches array is row-major (patches[v * cols + u]).
- Parameters:
patches— 2D array of Bezier surfaces (row-major order; must equalrows * cols);rows— patch row count;cols— patch column count. - Returns: Combined BSpline surface, or
nilif the count doesn’t matchrows * colsor joining fails. - OCCT:
GeomConvert_CompBezierSurfacesToBSplineSurface. - Example:
// Assume patches is a 2×2 grid of Bezier surfaces if let combined = Surface.joinBezierPatches(patches, rows: 2, cols: 2) { let face = combined.toFace() }
convertToAnalytical(tolerance:)
Tries to recognise this BSpline or Bezier surface as a plane, cylinder, cone, sphere, or torus.
public func convertToAnalytical(tolerance: Double = 1e-4) -> AnalyticalConversion?
- Parameters:
tolerance— recognition tolerance. - Returns:
AnalyticalConversionwith the recognised surface and itsgap(max deviation), ornilif not recognisable. - OCCT:
ShapeCustom_Surface::ConvertToAnalytical. - Example:
if let result = surf.convertToAnalytical(tolerance: 1e-4) { print("recognised surface, gap:", result.gap) }
splitByContinuity(criterion:tolerance:)
Analyses and splits a BSpline surface at continuity breaks.
public func splitByContinuity(criterion: Int = 2, tolerance: Double = 1e-6) -> ContinuitySplitResult
- Parameters:
criterion— continuity level (0=C0, 1=C1, 2=C2, 3=C3);tolerance— tolerance for continuity checking. - Returns:
ContinuitySplitResultwithwasSplit,alreadyMeetsCriterion,uSplitCount, andvSplitCount. - OCCT:
BSplSLib::SplitByContinuity. - Example:
let r = surf.splitByContinuity(criterion: 2) if r.alreadyMeetsCriterion { print("surface is already C2") } else { print("needs \(r.uSplitCount) U splits and \(r.vSplitCount) V splits") }
LocalAnalysis
continuityWith(_:u1:v1:u2:v2:order:)
Analyses the geometric continuity between this surface at (u1, v1) and another surface at (u2, v2).
public func continuityWith(
_ other: Surface,
u1: Double, v1: Double,
u2: Double, v2: Double,
order: Int = 4
) -> ContinuityAnalysis?
Returns C0, G1, C1, G2, C2 status in a single call. The ContinuityAnalysis struct exposes both raw angular values and Boolean convenience flags (isC0, isG1, isC1, isG2, isC2).
- Parameters:
other— second surface;u1,v1— UV parameters on this surface;u2,v2— UV parameters onother;order— maximum order to check (0=C0 … 4=C2). - Returns:
ContinuityAnalysis, ornilif analysis fails. - OCCT:
LocalAnalysis_SurfaceContinuity. - Example:
if let ca = surf1.continuityWith(surf2, u1: 1.0, v1: 0.5, u2: 0.0, v2: 0.5) { #expect(ca.isG1) print("C0 gap:", ca.c0Value, "G1 angle:", ca.g1Angle) }
GeomFill_NSections (v0.68.0)
Surface.nSections(curves:params:)
Creates a BSpline surface by lofting through N section curves at specified parameter values.
public static func nSections(curves: [Curve3D], params: [Double]) -> Surface?
curves and params must have the same length (minimum 2). The params array assigns a V parameter to each section, typically in 0...1 order.
- Parameters:
curves— section curves (minimum 2);params— V parameter for each section (same count ascurves). - Returns: BSpline surface, or
nilif counts don’t match orGeomFill_NSectionsfails. - OCCT:
GeomFill_NSections. - Example:
guard let c1 = Curve3D.interpolate(points: [SIMD3(0,0,0), SIMD3(5,0,0), SIMD3(10,0,0)]), let c2 = Curve3D.interpolate(points: [SIMD3(0,5,2), SIMD3(5,5,4), SIMD3(10,5,2)]) else { return } if let surf = Surface.nSections(curves: [c1, c2], params: [0, 1]) { let face = surf.toFace() }
Surface.nSectionsInfo(curves:params:)
Queries the pole count, knot count, and degree that nSections would produce, without building the surface.
public static func nSectionsInfo(
curves: [Curve3D],
params: [Double]
) -> (poleCount: Int, knotCount: Int, degree: Int)?
- Parameters:
curves— section curves (minimum 2);params— V parameters (same count). - Returns: Tuple of
(poleCount, knotCount, degree), ornilon failure. - OCCT:
GeomFill_NSections(introspection without surface extraction). - Example:
if let info = Surface.nSectionsInfo(curves: [c1, c2], params: [0, 1]) { print("poles:", info.poleCount, "degree:", info.degree) }
NLPlate G2/G3, IncrementalSolve, GeomFill_Generator (v0.69.0)
nlPlateDeformedG2(constraints:maxIterations:tolerance:)
Deforms this surface with position, tangent, and curvature constraints (NLPlate G0+G2).
public func nlPlateDeformedG2(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>,
tangentU: SIMD3<Double>, tangentV: SIMD3<Double>,
curvatureUU: SIMD3<Double>, curvatureUV: SIMD3<Double>, curvatureVV: SIMD3<Double>)],
maxIterations: Int = 4,
tolerance: Double = 1e-3
) -> Surface?
Extends nlPlateDeformedG1 by also constraining the second derivatives (curvature tensors) at each point. Produces curvature-continuous deformations. Each constraint carries 20 doubles.
- Parameters:
constraints— array of constraint tuples (non-empty);maxIterations— solver iteration limit;tolerance— approximation tolerance. - Returns: New deformed surface, or
nilon failure. - OCCT:
NLPlate_NLPlate+NLPlate_HPG2Constraint+GeomPlate_MakeApprox. - Example:
if let deformed = surf.nlPlateDeformedG2(constraints: [( uv: SIMD2(0.5, 0.5), target: SIMD3(5, 5, 3), tangentU: SIMD3(1, 0, 0), tangentV: SIMD3(0, 1, 0), curvatureUU: .zero, curvatureUV: .zero, curvatureVV: .zero )]) { let face = deformed.toFace() }
nlPlateDeformedG3(constraints:maxIterations:tolerance:)
Deforms this surface with G0+G1+G2+G3 constraints (position, tangent, curvature, and third-order derivatives).
public func nlPlateDeformedG3(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>,
tangentU: SIMD3<Double>, tangentV: SIMD3<Double>,
curvatureUU: SIMD3<Double>, curvatureUV: SIMD3<Double>, curvatureVV: SIMD3<Double>,
d3UUU: SIMD3<Double>, d3UUV: SIMD3<Double>, d3UVV: SIMD3<Double>, d3VVV: SIMD3<Double>)],
maxIterations: Int = 4,
tolerance: Double = 1e-3
) -> Surface?
The highest-order NLPlate constraint set: 32 doubles per constraint (uv + target + 3 first derivatives + 3 second derivatives + 4 third derivatives). Achieves G3-continuous deformations.
- Parameters:
constraints— G0+G1+G2+G3 constraint tuples (non-empty);maxIterations— solver iteration limit;tolerance— approximation tolerance. - Returns: New deformed surface, or
nilon failure. - OCCT:
NLPlate_NLPlate+NLPlate_HPG3Constraint+GeomPlate_MakeApprox. - Example:
if let deformed = surf.nlPlateDeformedG3(constraints: [( uv: SIMD2(0.5, 0.5), target: SIMD3(5, 5, 3), tangentU: SIMD3(1, 0, 0), tangentV: SIMD3(0, 1, 0), curvatureUU: .zero, curvatureUV: .zero, curvatureVV: .zero, d3UUU: .zero, d3UUV: .zero, d3UVV: .zero, d3VVV: .zero )]) { let face = deformed.toFace() }
nlPlateDeformedIncremental(constraints:maxOrder:initConstraintOrder:nbIncrements:)
Deforms this surface with G0 constraints using the incremental NLPlate solver strategy.
public func nlPlateDeformedIncremental(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>)],
maxOrder: Int = 2,
initConstraintOrder: Int = 1,
nbIncrements: Int = 4
) -> Surface?
Progressively adds constraints for better convergence on challenging constraint sets where the standard nlPlateDeformed may not converge well.
- Parameters:
constraints— G0 constraint pairs (non-empty);maxOrder— maximum polynomial order;initConstraintOrder— initial constraint order;nbIncrements— number of increments. - Returns: New deformed surface, or
nilon failure. - OCCT:
NLPlate_NLPlate::IncrementalSolve+GeomPlate_MakeApprox. - Example:
if let deformed = surf.nlPlateDeformedIncremental( constraints: [(uv: SIMD2(0.5, 0.5), target: SIMD3(5, 5, 3))], nbIncrements: 6 ) { let face = deformed.toFace() }
nlPlateDerivative(constraints:u:v:iu:iv:)
Evaluates the partial derivative of the NLPlate G0 displacement field at a UV point.
public func nlPlateDerivative(
constraints: [(uv: SIMD2<Double>, target: SIMD3<Double>)],
u: Double, v: Double,
iu: Int = 1, iv: Int = 0
) -> SIMD3<Double>?
Solves the NLPlate problem with the given G0 constraints and returns the (iu, iv)-th partial derivative at (u, v) without approximating the surface.
- Parameters:
constraints— G0 constraint pairs;u,v— evaluation parameters;iu,iv— derivative orders in U and V. - Returns: Derivative vector, or
nilon failure. - OCCT:
NLPlate_NLPlate::Evaluate. - Example:
if let d = surf.nlPlateDerivative( constraints: [(uv: SIMD2(0.5, 0.5), target: SIMD3(5, 5, 2))], u: 0.5, v: 0.5, iu: 1, iv: 0 ) { print("dU displacement at (0.5, 0.5):", d) }
Surface.generatedFromSections(curves:tolerance:)
Generates a ruled/lofted surface from a sequence of section curves using linear interpolation in V.
public static func generatedFromSections(
curves: [Curve3D],
tolerance: Double = 1e-6
) -> Surface?
Uses GeomFill_Generator (linear V-direction interpolation), which is simpler and faster than nSections but less flexible — the V blending is always linear between consecutive sections.
- Parameters:
curves— section curves (minimum 2);tolerance— parametric tolerance. - Returns: Generated surface, or
nilif fewer than 2 curves orGeomFill_Generatorfails. - OCCT:
GeomFill_Generator. - Example:
guard let c1 = Curve3D.interpolate(points: [SIMD3(0,0,0), SIMD3(10,0,0)]), let c2 = Curve3D.interpolate(points: [SIMD3(0,5,3), SIMD3(10,5,3)]) else { return } if let surf = Surface.generatedFromSections(curves: [c1, c2]) { let face = surf.toFace() }
Surface.degeneratedBoundaryValue(point:first:last:parameter:)
Evaluates a degenerated boundary (a boundary that has collapsed to a single point) at a parameter.
public static func degeneratedBoundaryValue(
point: SIMD3<Double>,
first: Double = 0,
last: Double = 1,
parameter: Double
) -> SIMD3<Double>
Returns point regardless of parameter — models the apex of a cone or any other degenerate pole boundary.
- Parameters:
point— the degenerate point;first,last— parameter range;parameter— evaluation parameter. - Returns: The degenerate point (always equal to
point). - OCCT:
GeomFill_DegeneratedBound::Value. - Example:
let apex = Surface.degeneratedBoundaryValue( point: SIMD3(0, 0, 10), first: 0, last: 1, parameter: 0.5 ) // apex == SIMD3(0, 0, 10)
Surface.isDegeneratedBoundary(point:first:last:)
Returns true — always, for degenerated boundaries defined by a single point.
public static func isDegeneratedBoundary(
point: SIMD3<Double>,
first: Double = 0,
last: Double = 1
) -> Bool
- Parameters:
point— the degenerate point;first,last— parameter range. - Returns: Always
true. - OCCT:
GeomFill_DegeneratedBound::IsDegenerated. - Note: Provided for API completeness when working with
GeomFillboundary objects.
boundaryWithSurfaceEvaluate(curve2d:first:last:parameter:)
Evaluates a boundary-with-surface (a 2D curve on this surface) at a parameter, returning the 3D point and surface normal.
public func boundaryWithSurfaceEvaluate(
curve2d: Curve2D,
first: Double,
last: Double,
parameter: Double
) -> (point: SIMD3<Double>, normal: SIMD3<Double>)?
- Parameters:
curve2d— a 2D curve lying on this surface;first,last— parameter range of the 2D curve;parameter— evaluation parameter. - Returns: Tuple of
(point, normal)at the boundary parameter, ornilon failure. - OCCT:
GeomFill_BoundWithSurf::Value+ normal from the host surface. - Example:
if let seg = Curve2D.segment(from: SIMD2(0, 0), to: SIMD2(1, 0)), let (pt, n) = surf.boundaryWithSurfaceEvaluate(curve2d: seg, first: 0, last: 1, parameter: 0.5) { print("boundary point:", pt, "normal:", n) }
Surface.averagePlane(points:boundaryPointCount:tolerance:)
Computes the average plane through a set of 3D points.
public static func averagePlane(
points: [SIMD3<Double>],
boundaryPointCount: Int? = nil,
tolerance: Double = 1e-3
) -> AveragePlaneResult?
Returns the plane normal, origin, and UV bounding box. Also handles the collinear case, returning isLine == true with a line origin and direction.
- Parameters:
points— 3D points (minimum 3);boundaryPointCount— number of boundary points used for orientation (defaults to all points);tolerance— planarity check tolerance. - Returns:
AveragePlaneResult, ornilif the point set is degenerate. - OCCT:
GeomPlate_BuildAveragePlane. - Example:
let pts: [SIMD3<Double>] = [.zero, SIMD3(10,0,0), SIMD3(0,10,0), SIMD3(10,10,0.1)] if let result = Surface.averagePlane(points: pts) { if result.isPlane { print("normal:", result.normal) } }
Surface.plateErrors(points:tolerance:maxDegree:maxSegments:)
Builds a plate surface through points and reports G0, G1, and G2 approximation errors.
public static func plateErrors(
points: [SIMD3<Double>],
tolerance: Double = 1e-3,
maxDegree: Int = 8,
maxSegments: Int = 9
) -> (g0Error: Double, g1Error: Double, g2Error: Double)?
- Parameters:
points— 3D points (minimum 3);tolerance— approximation tolerance;maxDegree— maximum BSpline degree;maxSegments— maximum BSpline segments. - Returns: Tuple of positional (
g0Error), tangential (g1Error), and curvature (g2Error) errors, ornilon failure. - OCCT:
GeomPlate_BuildPlateSurface+GeomPlate_MakeApprox(error query). - Example:
if let err = Surface.plateErrors(points: pts) { print("G0:", err.g0Error, "G1:", err.g1Error, "G2:", err.g2Error) }
Extrema, gce Factories, GeomTools Persistence (v0.80.0)
extremaPS(point:)
Computes point-to-surface extrema (nearest/farthest points).
public func extremaPS(point: SIMD3<Double>) -> PointSurfaceExtrema
- Parameters:
point— the query point. - Returns:
PointSurfaceExtremawithisDoneandcount(number of extremum solutions). - OCCT:
Extrema_ExtPS. - Example:
let e = surf.extremaPS(point: SIMD3(5, 5, 10)) if e.isDone { for i in 1...e.count { let p = surf.extremaPSPoint(point: SIMD3(5, 5, 10), index: i) print("dist²:", p.squareDistance, "uv:", p.u, p.v) } }
extremaPSPoint(point:index:)
Returns the Nth extremum from a point-surface extrema computation (1-based).
public func extremaPSPoint(point: SIMD3<Double>, index: Int) -> ExtremaPointOnSurface
- Parameters:
point— the query point;index— 1-based extremum index. - Returns:
ExtremaPointOnSurfacewithsquareDistance,point,u, andv. - OCCT:
Extrema_ExtPS::Point/SquareDistance. - Note: Call
extremaPS(point:)first to confirmisDoneand obtain the validcount.
extremaSS(other:)
Computes surface-to-surface extrema.
public func extremaSS(other: Surface) -> SurfaceSurfaceExtrema
- Parameters:
other— the second surface. - Returns:
SurfaceSurfaceExtremawithisDone,isParallel, andcount. - OCCT:
Extrema_ExtSS. - Example:
let e = surf1.extremaSS(other: surf2) if e.isDone, !e.isParallel { for i in 1...e.count { let pair = surf1.extremaSSPoint(other: surf2, index: i) print("dist²:", pair.squareDistance) } }
extremaSSPoint(other:index:)
Returns the Nth extremum pair from a surface-surface extrema computation.
public func extremaSSPoint(other: Surface, index: Int) -> Curve3D.ExtremaPointPair
- Parameters:
other— the second surface;index— 1-based extremum index. - Returns:
Curve3D.ExtremaPointPairwithsquareDistance,point1,param1,point2,param2. - OCCT:
Extrema_ExtSS::Points/SquareDistance.
Surface.coneFrom2PointsRadii(p1:p2:radius1:radius2:)
Creates a conical surface from 2 axis points and 2 radii using the gce_MakeCone factory.
public static func coneFrom2PointsRadii(
p1: SIMD3<Double>,
p2: SIMD3<Double>,
radius1: Double,
radius2: Double
) -> Surface?
- Parameters:
p1,p2— axis points;radius1— radius atp1;radius2— radius atp2. - Returns: Conical surface, or
nilon failure. - OCCT:
gce_MakeCone(gp_Pnt, gp_Pnt, Standard_Real, Standard_Real). - Example:
if let cone = Surface.coneFrom2PointsRadii( p1: .zero, p2: SIMD3(0, 0, 10), radius1: 5, radius2: 2 ) { let face = cone.toFace() }
Surface.cylinderFrom3Points(p1:p2:p3:)
Creates a cylindrical surface from 3 points using the gce_MakeCylinder factory.
public static func cylinderFrom3Points(
p1: SIMD3<Double>,
p2: SIMD3<Double>,
p3: SIMD3<Double>
) -> Surface?
The axis passes through p1 and p2; p3 defines the radius (its distance to the axis).
- Parameters:
p1,p2— axis points;p3— radius-defining point. - Returns: Cylindrical surface, or
nilon failure. - OCCT:
gce_MakeCylinder(gp_Pnt, gp_Pnt, gp_Pnt). - Example:
if let cyl = Surface.cylinderFrom3Points( p1: .zero, p2: SIMD3(0, 0, 10), p3: SIMD3(5, 0, 0) ) { let face = cyl.toFace(uRange: 0...2 * .pi, vRange: 0...10) }
Surface.planeFromEquation(a:b:c:d:)
Creates a plane surface from the equation Ax + By + Cz + D = 0.
public static func planeFromEquation(
a: Double, b: Double, c: Double, d: Double
) -> Surface?
- Parameters:
a,b,c— normal direction coefficients;d— plane offset. - Returns: Plane surface, or
nilon failure. - OCCT:
gce_MakePln(Standard_Real, Standard_Real, Standard_Real, Standard_Real). - Example:
// XY plane at Z = 5: 0x + 0y + 1z - 5 = 0 if let plane = Surface.planeFromEquation(a: 0, b: 0, c: 1, d: -5) { let face = plane.toFace(uRange: -10...10, vRange: -10...10) }
Surface.planeFrom3Points(p1:p2:p3:)
Creates a plane surface from 3 points using the gce_MakePln factory.
public static func planeFrom3Points(
p1: SIMD3<Double>,
p2: SIMD3<Double>,
p3: SIMD3<Double>
) -> Surface?
- Parameters:
p1,p2,p3— three non-collinear points. - Returns: Plane surface, or
nilif points are collinear. - OCCT:
gce_MakePln(gp_Pnt, gp_Pnt, gp_Pnt). - Example:
if let plane = Surface.planeFrom3Points( p1: .zero, p2: SIMD3(10, 0, 0), p3: SIMD3(0, 10, 0) ) { let face = plane.toFace(uRange: 0...10, vRange: 0...10) }
Surface.serializeSurfaces(_:)
Serialises an array of surfaces to a string using GeomTools_SurfaceSet.
public static func serializeSurfaces(_ surfaces: [Surface]) -> String?
The produced string can be stored and later restored with deserializeSurfaces(_:). Uses OCCT’s native binary-text stream format.
- Parameters:
surfaces— array of surfaces to serialise. - Returns: Serialised string, or
nilon failure. - OCCT:
GeomTools_SurfaceSet::Write. - Example:
if let data = Surface.serializeSurfaces([surf1, surf2]) { // save data to disk if let restored = Surface.deserializeSurfaces(data) { print("restored \(restored.count) surfaces") } }
Surface.deserializeSurfaces(_:)
Deserialises surfaces from a string produced by serializeSurfaces(_:).
public static func deserializeSurfaces(_ data: String) -> [Surface]?
- Parameters:
data— string produced byserializeSurfaces(_:). - Returns: Array of restored surfaces, or
nilif parsing fails or the string is empty. - OCCT:
GeomTools_SurfaceSet::Read. - Example:
if let surfaces = Surface.deserializeSurfaces(savedData) { for s in surfaces { let face = s.toFace() } }