Link Search Menu Expand Document

Surfaces from Points

Given a set of 3D points, OCCTSwift can fit a smooth B-spline Surface through them. There are two cases — and they take different functions:

  • A regular grid of samples (rows × columns — a height field, a scan) → Surface.fromPointGrid (GeomAPI_PointsToBSplineSurface).
  • A scattered cloud with no grid structure → Surface.plateThrough (GeomPlate).

Both return a Surface; call .toFace() to get a renderable / sewable Shape.

A grid of samples → fromPointGrid

When the points form a topological grid, pass them row-major (point[v*uCount + u]) with the row and column counts. The result approximates the points within tolerance:

var pts = [SIMD3<Double>]()
let n = 6
for v in 0..<n {
    for u in 0..<n {
        let x = Double(u) * 4, y = Double(v) * 4
        pts.append(SIMD3(x, y, 3 * sin(x * 0.3) * cos(y * 0.3)))   // a wavy height field
    }
}

guard let surface = Surface.fromPointGrid(points: pts, uCount: n, vCount: n,
                                          degMin: 3, degMax: 8,
                                          continuity: 2, tolerance: 1e-3) else { return }
let face = surface.toFace()

It approximates (not strictly interpolates): tighten tolerance to pull the surface closer to the samples, raise degMax for more flexibility. points.count must equal uCount * vCount.


fromPointGrid — a B-spline through a 6×6 height field

A scattered cloud → plateThrough

When the points have no grid order, the plate surface (GeomPlate_BuildPlateSurface) builds a smooth, energy-minimizing B-spline through them — minimum 3 points:

let points: [SIMD3<Double>] = [
    SIMD3(0, 0, 0), SIMD3(10, 0, 1), SIMD3(10, 10, 2),
    SIMD3(0, 10, 1), SIMD3(5, 5, 3),     // a high point in the middle
]
guard let plate = Surface.plateThrough(points, degree: 3, tolerance: 0.01) else { return }

plateThrough doesn’t need any ordering or counts — it’s the right tool for an irregular set of constraint points (probe data, feature points). The trade-off is less direct control over the parametrization than the grid fit gives you.

Deform an existing surface to hit target points

If you already have a surface and want to pull it through specific positions, the non-linear plate solver deforms it to meet (u, v) → target constraints:

let plane = Surface.plane(origin: .zero, normal: SIMD3(0, 0, 1))!
let bumped = plane.nlPlateDeformed(
    constraints: [(uv: SIMD2(0, 0), target: SIMD3(0, 0, 5))],   // lift the centre to z = 5
    maxIterations: 4, tolerance: 1e-3)

This keeps the surface’s existing shape and only displaces it to satisfy the constraints — distinct from fitting a fresh surface to a point set. (A G0+G1 variant also takes tangent constraints.)

Which to use

You have Use
Points on a regular grid (rows × cols) Surface.fromPointGrid
A scattered point cloud Surface.plateThrough
An existing surface to pull through target points surface.nlPlateDeformed
A wireframe of curves (profiles × guides) Surface.gordon

See also