Link Search Menu Expand Document

Curve2D

A Curve2D is a parametric 2D curve — the Swift analog of OCCT’s Geom2d_Curve class hierarchy. It wraps lines, segments, circles, arcs, ellipses, parabolas, hyperbolas, BSplines, and Bezier curves polymorphically behind a single opaque handle. Curve2D instances are used as pcurves (parameter-space curves on surfaces), 2D profiles, and constraint inputs. Obtain one via the static factory methods on Curve2D, Curve2DGcc, or by evaluating an existing curve at a point.

Note: Curve2D is documented across several pages — see also Curve2D — Analytic Types, Curve2D — Analysis, and Curve2D — Constraint Solvers.

Topics


Properties

domain

The parametric domain of the curve as a closed range [first, last].

public var domain: ClosedRange<Double> { get }

Use domain.lowerBound and domain.upperBound when calling point(at:), d1(at:), or any parameter-based method.

  • Returns: Closed range of valid parameter values.
  • OCCT: Geom2d_Curve::FirstParameter / LastParameter.
  • Example:
    let arc = Curve2D.arcOfCircle(center: .zero, radius: 5, startAngle: 0, endAngle: .pi)!
    let d = arc.domain   // 0...π
    let mid = arc.point(at: (d.lowerBound + d.upperBound) / 2)
    

isClosed

Whether the curve forms a closed loop.

public var isClosed: Bool { get }
  • OCCT: Geom2d_Curve::IsClosed.
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    #expect(circle.isClosed == true)
    

isPeriodic

Whether the curve is periodic (e.g. a full circle or ellipse).

public var isPeriodic: Bool { get }
  • OCCT: Geom2d_Curve::IsPeriodic.
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    #expect(seg.isPeriodic == false)
    

period

The period of the curve, or nil if the curve is not periodic.

public var period: Double? { get }
  • Returns: Period value, or nil if isPeriodic is false.
  • OCCT: Geom2d_Curve::Period.
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    if let p = circle.period { print(p) }  // ≈ 2π
    

startPoint

The point at the start of the parameter domain.

public var startPoint: SIMD2<Double> { get }

Convenience for point(at: domain.lowerBound).

  • OCCT: Geom2d_Curve::Value(FirstParameter).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(1, 2), to: SIMD2(4, 5))!
    print(seg.startPoint)  // SIMD2(1.0, 2.0)
    

endPoint

The point at the end of the parameter domain.

public var endPoint: SIMD2<Double> { get }

Convenience for point(at: domain.upperBound).

  • OCCT: Geom2d_Curve::Value(LastParameter).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(1, 2), to: SIMD2(4, 5))!
    print(seg.endPoint)  // SIMD2(4.0, 5.0)
    

Evaluation

point(at:)

Evaluates the 2D curve position at a parameter.

public func point(at u: Double) -> SIMD2<Double>
  • Parameters: u — parameter value within domain.
  • Returns: 2D point on the curve.
  • OCCT: Geom2d_Curve::Value(u).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    let mid = seg.point(at: (seg.domain.lowerBound + seg.domain.upperBound) / 2)
    // mid ≈ SIMD2(5, 0)
    

d1(at:)

Evaluates the position and first derivative (tangent) at a parameter.

public func d1(at u: Double) -> (point: SIMD2<Double>, tangent: SIMD2<Double>)

The tangent vector is not normalised — its magnitude depends on the parameterisation.

  • Parameters: u — parameter value within domain.
  • Returns: Tuple of position and first-derivative vector.
  • OCCT: Geom2d_Curve::D1(u, P, V1).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    let (pos, tan) = circle.d1(at: 0)
    

d2(at:)

Evaluates position, first derivative, and second derivative at a parameter.

public func d2(at u: Double) -> (point: SIMD2<Double>, d1: SIMD2<Double>, d2: SIMD2<Double>)
  • Parameters: u — parameter value within domain.
  • Returns: Tuple of position, first derivative, and second derivative.
  • OCCT: Geom2d_Curve::D2(u, P, V1, V2).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    let (pt, v1, v2) = seg.d2(at: 0)
    // v2 ≈ SIMD2(0, 0) — zero second derivative for a line
    

Primitive Curves

Curve2D.line(through:direction:)

Creates an infinite line through a point in a direction.

public static func line(through point: SIMD2<Double>, direction: SIMD2<Double>) -> Curve2D?

The curve is unbounded; its domain is (-∞, +∞). Use segment(from:to:) for a bounded segment.

  • Parameters: point — a point on the line; direction — line direction (need not be normalised).
  • Returns: Infinite line curve, or nil if direction is zero.
  • OCCT: Geom2d_Line(gp_Lin2d(point, direction)).
  • Example:
    let line = Curve2D.line(through: .zero, direction: SIMD2(1, 0))
    

Curve2D.segment(from:to:)

Creates a bounded line segment between two points.

public static func segment(from p1: SIMD2<Double>, to p2: SIMD2<Double>) -> Curve2D?
  • Parameters: p1 — start point; p2 — end point.
  • Returns: Segment curve, or nil if the points coincide.
  • OCCT: Geom2d_TrimmedCurve wrapping a Geom2d_Line.
  • Example:
    let seg = Curve2D.segment(from: SIMD2(0, 0), to: SIMD2(10, 5))!
    print(seg.length!)  // ≈ 11.18
    

Curve2D.circle(center:radius:)

Creates a full (untrimmed) circle.

public static func circle(center: SIMD2<Double>, radius: Double) -> Curve2D?

The circle is periodic with period . U=0 starts on the positive X axis of the local frame.

  • Parameters: center — circle centre; radius — circle radius (must be > 0).
  • Returns: Full circle curve, or nil if radius ≤ 0.
  • OCCT: Geom2d_Circle(gp_Circ2d(...)).
  • See also: circleFromCenterRadius(center:radius:) builds the identical circle through OCCT’s gce_MakeCirc2d algorithm and enforces the same radius > 0 contract (#411).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    #expect(circle.isClosed)
    

Curve2D.arcOfCircle(center:radius:startAngle:endAngle:)

Creates a circular arc between two angles.

public static func arcOfCircle(center: SIMD2<Double>, radius: Double,
                               startAngle: Double, endAngle: Double) -> Curve2D?
  • Parameters: center — circle centre; radius — radius (> 0); startAngle — start angle in radians; endAngle — end angle in radians.
  • Returns: Circular arc, or nil on failure.
  • OCCT: GCE2d_MakeArcOfCircleGeom2d_TrimmedCurve.
  • Example:
    let arc = Curve2D.arcOfCircle(center: .zero, radius: 5,
                                   startAngle: 0, endAngle: .pi / 2)!
    

Curve2D.arcThrough(_:_:_:)

Creates a circular arc passing through three points.

public static func arcThrough(_ p1: SIMD2<Double>, _ p2: SIMD2<Double>,
                              _ p3: SIMD2<Double>) -> Curve2D?

OCCT derives the centre and radius from the three points. The arc sweeps from p1 through p2 to p3.

  • Parameters: p1 — start point; p2 — interior point; p3 — end point.
  • Returns: Arc curve, or nil if points are collinear or coincident.
  • OCCT: GCE2d_MakeArcOfCircle(p1, p2, p3)Geom2d_TrimmedCurve.
  • Example:
    let arc = Curve2D.arcThrough(SIMD2(5, 0), SIMD2(0, 5), SIMD2(-5, 0))
    

Curve2D.ellipse(center:majorRadius:minorRadius:rotation:)

Creates a full ellipse.

public static func ellipse(center: SIMD2<Double>, majorRadius: Double,
                           minorRadius: Double, rotation: Double = 0) -> Curve2D?
  • Parameters: center — ellipse centre; majorRadius — semi-major axis (must be > 0 and ≥ minorRadius); minorRadius — semi-minor axis (must be > 0); rotation — rotation of the major axis from the X axis in radians (default 0).
  • Returns: Full ellipse curve, or nil if either radius is ≤ 0 or minorRadius exceeds majorRadius. Equal radii are valid.
  • OCCT: Geom2d_Ellipse(gp_Elips2d(...)).
  • See also: ellipseFromCenterDir(center:direction:majorRadius:minorRadius:) builds the identical ellipse through OCCT’s gce_MakeElips2d algorithm and enforces the same radius contract (#487).
  • Example:
    let ellipse = Curve2D.ellipse(center: .zero, majorRadius: 10, minorRadius: 5)!
    Curve2D.ellipse(center: .zero, majorRadius: 5, minorRadius: 10)  // nil, minor exceeds major
    

Curve2D.arcOfEllipse(center:majorRadius:minorRadius:rotation:startAngle:endAngle:)

Creates an elliptical arc between two angles.

public static func arcOfEllipse(center: SIMD2<Double>, majorRadius: Double,
                                minorRadius: Double, rotation: Double = 0,
                                startAngle: Double, endAngle: Double) -> Curve2D?
  • Parameters: center — centre; majorRadius — semi-major axis; minorRadius — semi-minor axis; rotation — major-axis rotation in radians (default 0); startAngle/endAngle — arc bounds in radians.
  • Returns: Elliptical arc, or nil on failure.
  • OCCT: GCE2d_MakeArcOfEllipseGeom2d_TrimmedCurve.
  • Example:
    let arc = Curve2D.arcOfEllipse(center: .zero, majorRadius: 10, minorRadius: 5,
                                    startAngle: 0, endAngle: .pi)
    

Curve2D.parabola(focus:direction:focalLength:)

Creates a parabola.

public static func parabola(focus: SIMD2<Double>, direction: SIMD2<Double>,
                            focalLength: Double) -> Curve2D?
  • Parameters: focus — focus point; direction — axis direction from vertex toward focus; focalLength — distance from vertex to focus (must be > 0).
  • Returns: Parabola curve, or nil if focalLength ≤ 0.
  • OCCT: Geom2d_Parabola(gp_Parab2d(...)).
  • See also: parabolaFromCenterDir(center:direction:focal:) places the same curve through OCCT’s gce_MakeParab2d algorithm, taking the vertex rather than the focus, and enforces the same focal-length contract (#487).
  • Example:
    let par = Curve2D.parabola(focus: SIMD2(0, 2), direction: SIMD2(0, 1), focalLength: 2)
    Curve2D.parabola(focus: .zero, direction: SIMD2(0, 1), focalLength: 0)  // nil, a line
    

Curve2D.hyperbola(center:majorRadius:minorRadius:rotation:)

Creates a hyperbola.

public static func hyperbola(center: SIMD2<Double>, majorRadius: Double,
                             minorRadius: Double, rotation: Double = 0) -> Curve2D?
  • Parameters: center — hyperbola centre; majorRadius — real semi-axis; minorRadius — imaginary semi-axis (both must be > 0, in either order); rotation — major-axis rotation in radians (default 0).
  • Returns: Hyperbola curve, or nil if either radius is ≤ 0. Unlike an ellipse, a minor radius larger than the major is valid.
  • OCCT: Geom2d_Hyperbola(gp_Hypr2d(...)).
  • See also: hyperbolaFromCenterDir(center:direction:majorRadius:minorRadius:) builds the identical hyperbola through OCCT’s gce_MakeHypr2d algorithm and enforces the same radius contract (#487).
  • Example:
    let hyp = Curve2D.hyperbola(center: .zero, majorRadius: 3, minorRadius: 2)
    Curve2D.hyperbola(center: .zero, majorRadius: 2, minorRadius: 3)  // valid, not inverted
    

Draw (Discretization for Metal)

drawAdaptive(angularDeflection:chordalDeflection:maxPoints:)

Adaptively discretizes the curve using angular and chordal deflection criteria.

public func drawAdaptive(angularDeflection: Double = 0.1,
                         chordalDeflection: Double = 0.01,
                         maxPoints: Int = 4096) -> [SIMD2<Double>]

Concentrates sample points where curvature is high and fewer where the curve is straight, producing an efficient polyline for Metal rendering.

  • Parameters: angularDeflection — maximum angle between consecutive tangents (radians); chordalDeflection — maximum chord-to-curve deviation; maxPoints — output capacity, clamped into 0...Sampling.maximumSampleCount (10,000,000), so an unservable capacity returns the same points rather than a coarser sampling; 0 or less returns empty (#558). The deflection criteria decide the actual point count.
  • Returns: Array of 2D points along the curve; empty on failure.
  • OCCT: GCPnts_TangentialDeflection (via OCCTCurve2DDrawAdaptive).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    let pts = circle.drawAdaptive(angularDeflection: 0.05, chordalDeflection: 0.005)
    // pts suitable for Metal vertex buffer
    

drawUniform(pointCount:)

Discretizes the curve at up to pointCount uniformly-spaced arc-length points. The first point is always the start of the curve and the last is always its end.

public func drawUniform(pointCount: Int) -> [SIMD2<Double>]
  • Parameters: pointCount, the desired number of output points — a request, honoured within 2...Sampling.maximumSampleCount (10,000,000); outside that range the result is empty (#501, #558). Not clamped: a count past the ceiling fails visibly rather than coming back coarser than what was asked for. Before #558 a negative aborted the process rather than returning empty.
  • Returns: Array of 2D points, never more than pointCount; empty on failure.
  • OCCT: GCPnts_UniformAbscissa (via OCCTCurve2DDrawUniform). It sizes its own array at pointCount + 5 and can report more points than requested on a poorly-conditioned curve; the surplus is dropped and the curve’s end point kept (#501).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    let pts = seg.drawUniform(pointCount: 11)
    // pts[5] ≈ SIMD2(5, 0)
    

drawDeflection(deflection:maxPoints:)

Discretizes the curve using a maximum chordal-deflection criterion.

public func drawDeflection(deflection: Double = 0.01,
                           maxPoints: Int = 4096) -> [SIMD2<Double>]
  • Parameters: deflection — maximum chord-to-curve deviation; maxPoints — output capacity, clamped into 0...Sampling.maximumSampleCount (10,000,000), so an unservable capacity returns the same points rather than a coarser sampling; 0 or less returns empty (#558).
  • Returns: Array of 2D points; empty on failure.
  • OCCT: GCPnts_UniformDeflection (via OCCTCurve2DDrawDeflection).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 10)!
    let pts = circle.drawDeflection(deflection: 0.01)
    

BSpline & Bezier

Curve2D.bspline(poles:weights:knots:multiplicities:degree:)

Creates a BSpline (or rational NURBS) curve from control points, knots, multiplicities, and degree.

public static func bspline(poles: [SIMD2<Double>], weights: [Double]? = nil,
                           knots: [Double], multiplicities: [Int32],
                           degree: Int) -> Curve2D?

When weights is nil all pole weights default to 1.0 (non-rational BSpline).

  • Parameters:
    • poles — control points (minimum 2).
    • weights — per-pole weights (nil = uniform 1.0).
    • knots — distinct knot values.
    • multiplicities — per-knot multiplicity.
    • degree — curve degree (≥ 1).
  • Returns: BSpline/NURBS curve, or nil if parameters are invalid.
  • OCCT: Geom2d_BSplineCurve(poles, knots, multiplicities, degree).
  • Example:
    let poles: [SIMD2<Double>] = [SIMD2(0, 0), SIMD2(5, 10), SIMD2(10, 0)]
    let knots = [0.0, 1.0]
    let mults: [Int32] = [4, 4]
    let bsp = Curve2D.bspline(poles: poles, knots: knots, multiplicities: mults, degree: 3)
    

Curve2D.bezier(poles:weights:)

Creates a Bezier curve from control points with optional rational weights.

public static func bezier(poles: [SIMD2<Double>], weights: [Double]? = nil) -> Curve2D?

The curve passes through the first and last pole. The degree equals poles.count − 1.

  • Parameters: poles — control points (minimum 2); weights — per-pole rational weights (nil = uniform 1.0).
  • Returns: Bezier curve, or nil if fewer than 2 poles or construction fails.
  • OCCT: Geom2d_BezierCurve(poles) or the weighted overload.
  • Example:
    let bez = Curve2D.bezier(poles: [SIMD2(0, 0), SIMD2(5, 10), SIMD2(10, 0)])!
    print(bez.startPoint)  // SIMD2(0, 0)
    

Curve2D.interpolate(through:closed:tolerance:)

Interpolates a smooth BSpline curve through the given points.

public static func interpolate(through points: [SIMD2<Double>], closed: Bool = false,
                               tolerance: Double = 1e-6) -> Curve2D?

The curve passes exactly through every point. Use closed: true for a periodic loop — interpolatePeriodic(points:tolerance:) is a spelling of exactly that case and delegates here (#412).

  • Parameters: points — interpolation points (minimum 2); closed — closed/periodic curve; tolerance — point coincidence tolerance.
  • Returns: Interpolated BSpline, or nil on failure.
  • OCCT: Geom2dAPI_Interpolate + Perform().
  • Example:
    let pts: [SIMD2<Double>] = [SIMD2(0, 0), SIMD2(5, 5), SIMD2(10, 0)]
    if let c = Curve2D.interpolate(through: pts) {
        print(c.point(at: c.domain.lowerBound))  // ≈ SIMD2(0, 0)
    }
    

Curve2D.interpolate(through:startTangent:endTangent:tolerance:)

Interpolates through points with constrained endpoint tangents.

public static func interpolate(through points: [SIMD2<Double>],
                               startTangent: SIMD2<Double>,
                               endTangent: SIMD2<Double>,
                               tolerance: Double = 1e-6) -> Curve2D?

interpolate(points:startTangent:endTangent:tolerance:) is a spelling of this with the points: argument label, and delegates here.

  • Parameters: points — interpolation points; startTangent — tangent at the first point; endTangent — tangent at the last point; tolerance — precision.
  • Returns: Interpolated BSpline, or nil on failure.
  • OCCT: Geom2dAPI_Interpolate::Load(startTangent, endTangent) + Perform().
  • Example:
    let pts: [SIMD2<Double>] = [SIMD2(0, 0), SIMD2(10, 10)]
    let c = Curve2D.interpolate(through: pts,
                                 startTangent: SIMD2(1, 0),
                                 endTangent: SIMD2(0, 1))
    

Curve2D.interpolate(through:tangents:closed:tolerance:)

Interpolates through points with per-point tangent constraints at arbitrary indices.

public static func interpolate(through points: [SIMD2<Double>],
                               tangents: [Int: SIMD2<Double>],
                               closed: Bool = false,
                               tolerance: Double = 1e-6) -> Curve2D?

Use this when you need tangent continuity at specific interior transition points — for example where a straight section meets a circular arc.

  • Parameters: points — interpolation points (≥ 2); tangents — dictionary mapping point index to unit tangent direction (unconstrained indices use C2); closed — closed/periodic curve; tolerance — coincidence tolerance.
  • Returns: Interpolated BSpline, or nil on failure.
  • OCCT: OCCTCurve2DInterpolateWithInteriorTangents.
  • Example:
    let pts: [SIMD2<Double>] = [SIMD2(0, 0), SIMD2(5, 5), SIMD2(10, 0)]
    let c = Curve2D.interpolate(through: pts, tangents: [1: SIMD2(1, 0)])
    

Curve2D.fit(through:minDegree:maxDegree:tolerance:)

Approximates a BSpline curve fitting through points within tolerance.

public static func fit(through points: [SIMD2<Double>], minDegree: Int = 3,
                       maxDegree: Int = 8, tolerance: Double = 1e-3) -> Curve2D?

Unlike interpolate, the fitted curve minimises squared error — it does not necessarily pass exactly through every point. Good for noisy data.

  • Parameters: points — data points; minDegree/maxDegree — degree range; tolerance — approximation error.
  • Returns: Approximating BSpline, or nil on failure.
  • OCCT: Geom2dAPI_PointsToBSpline (via OCCTCurve2DFitPoints).
  • Example:
    let pts: [SIMD2<Double>] = stride(from: 0.0, to: 10.0, by: 0.5).map {
        SIMD2($0, sin($0))
    }
    let c = Curve2D.fit(through: pts)
    

poleCount

The number of control points (poles), or nil if not a BSpline or Bezier.

public var poleCount: Int? { get }
  • Returns: Pole count, or nil.
  • OCCT: Geom2d_BSplineCurve::NbPoles / Geom2d_BezierCurve::NbPoles.
  • Example:
    let bez = Curve2D.bezier(poles: [SIMD2(0,0), SIMD2(5,5), SIMD2(10,0)])!
    #expect(bez.poleCount == 3)
    

poles

The control points (poles), or nil if not a BSpline or Bezier.

public var poles: [SIMD2<Double>]? { get }
  • Returns: Array of 2D control points, or nil.
  • OCCT: Geom2d_BSplineCurve::Poles / Geom2d_BezierCurve::Poles.
  • Example:
    let bez = Curve2D.bezier(poles: [SIMD2(0,0), SIMD2(5,5), SIMD2(10,0)])!
    if let pts = bez.poles { #expect(pts.count == 3) }
    

degree

The polynomial degree, or nil if not a BSpline or Bezier.

public var degree: Int? { get }
  • OCCT: Geom2d_BSplineCurve::Degree / Geom2d_BezierCurve::Degree.
  • Example:
    let bez = Curve2D.bezier(poles: [SIMD2(0,0), SIMD2(5,5), SIMD2(10,0)])!
    #expect(bez.degree == 2)
    

Operations

trimmed(from:to:)

Creates a trimmed copy of this curve between two parameters.

public func trimmed(from u1: Double, to u2: Double) -> Curve2D?
  • Parameters: u1 — lower trim parameter; u2 — upper trim parameter (must satisfy u1 < u2).
  • Returns: Trimmed curve, or nil on failure.
  • OCCT: Geom2d_TrimmedCurve(curve, u1, u2).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    let halfArc = circle.trimmed(from: 0, to: .pi)
    

offset(by:)

Creates an offset curve at the given distance.

public func offset(by distance: Double) -> Curve2D?

Positive distance offsets to the left of the curve direction.

  • Parameters: distance — signed offset distance.
  • Returns: Offset curve, or nil on failure.
  • OCCT: Geom2d_OffsetCurve(curve, distance).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    let parallel = seg.offset(by: 5)
    

reversed()

Creates a reversed copy of this curve (parameter direction flipped).

public func reversed() -> Curve2D?

Start and end points are swapped.

  • Returns: Reversed curve, or nil on failure.
  • OCCT: Geom2d_Curve::Reversed().
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    let rev = seg.reversed()!
    print(rev.startPoint)  // SIMD2(10, 0)
    

translated(by:)

Creates a translated copy of this curve.

public func translated(by delta: SIMD2<Double>) -> Curve2D?
  • Parameters: delta — translation vector.
  • Returns: Translated curve, or nil on failure.
  • OCCT: Geom2d_Curve::Translated(gp_Vec2d).
  • Example:
    let c = Curve2D.circle(center: .zero, radius: 5)!
    let moved = c.translated(by: SIMD2(10, 0))!
    print(moved.point(at: 0).x)  // ≈ 15.0
    

rotated(around:angle:)

Creates a rotated copy of this curve.

public func rotated(around center: SIMD2<Double>, angle: Double) -> Curve2D?
  • Parameters: center — rotation centre point; angle — rotation angle in radians.
  • Returns: Rotated curve, or nil on failure.
  • OCCT: Geom2d_Curve::Rotated(gp_Pnt2d, angle).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(1, 0), to: SIMD2(10, 0))!
    let rotated = seg.rotated(around: .zero, angle: .pi / 2)
    

scaled(from:factor:)

Creates a scaled copy of this curve.

public func scaled(from center: SIMD2<Double>, factor: Double) -> Curve2D?
  • Parameters: center — fixed point of scaling; factor — scale factor.
  • Returns: Scaled curve, or nil on failure.
  • OCCT: Geom2d_Curve::Scaled(gp_Pnt2d, factor).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(5, 0))!
    let doubled = seg.scaled(from: .zero, factor: 2)!
    print(doubled.length!)  // 10.0
    

mirrored(acrossLine:direction:)

Creates a copy mirrored across an axis line.

public func mirrored(acrossLine point: SIMD2<Double>, direction: SIMD2<Double>) -> Curve2D?
  • Parameters: point — a point on the mirror axis; direction — axis direction.
  • Returns: Mirrored curve, or nil on failure.
  • OCCT: Geom2d_Curve::Mirror(gp_Ax2d).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(0, 1), to: SIMD2(10, 1))!
    let mir = seg.mirrored(acrossLine: .zero, direction: SIMD2(1, 0))
    

mirrored(acrossPoint:)

Creates a copy mirrored through a point.

public func mirrored(acrossPoint point: SIMD2<Double>) -> Curve2D?
  • Parameters: point — the point of symmetry.
  • Returns: Mirrored curve, or nil on failure.
  • OCCT: Geom2d_Curve::Mirror(gp_Pnt2d).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(0, 0), to: SIMD2(4, 0))!
    let mir = seg.mirrored(acrossPoint: SIMD2(2, 0))!
    

length

The total arc length of the curve, or nil on error.

public var length: Double? { get }
  • Returns: Arc length in model units, or nil if measurement fails.
  • OCCT: GCPnts_AbscissaPoint::Length per GeomAbs_CN interval, subdivided until two successive levels agree to 1e-9 relative (#603). A line, a circle and a 2-pole Bezier/BSpline keep their exact closed form.
  • Note: A whole ellipse used to measure up to 1.7% long — one Gauss quadrature over the whole domain, the same defect and the same numbers as the 3D spelling, because both reach one GCPnts_AbscissaPoint::length template (#603).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(3, 4))!
    print(seg.length!)  // 5.0
    

length(from:to:)

Arc length between two parameter values. This is the canonical, failure-distinguishing entry point: arcLength(from:to:) delegates to it and collapses nil to a -1.0 sentinel for source compatibility (#549).

public func length(from u1: Double, to u2: Double) -> Double?
  • Parameters: u1 — start parameter, must be finite; u2 — end parameter, must be finite (either order).
  • Returns: Arc length, or nil on failure — never a sentinel value.
  • OCCT: GCPnts_AbscissaPoint::Length(adaptor, u1, u2), subdivided per GeomAbs_CN interval, the same measurement as length (#603).
  • Note: The range may be given in either order, and equal parameters measure 0.
  • Note: .nan and ±.infinity also report nil, on every curve type. They are rejected in the bridge, because OCCT’s integrator does not check them: on a multi-span BSpline a NaN upper bound measured 0 and a NaN lower bound the curve’s whole length — see Curve3D for the mechanism (#548).
  • Note: A range reaching outside the curve’s domain measures the part of it that lies on the curve (a range wholly outside measures 0); a curve whose domain covers a whole period measures the whole range and winds. Same rule and same shared implementation as the 3D spelling, so both answer identically on the same geometry (#600).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 1)!
    let d = circle.domain
    let halfLen = circle.length(from: d.lowerBound, to: d.lowerBound + .pi)
    // halfLen ≈ π
    let bad = circle.length(from: d.lowerBound, to: .nan)
    // bad == nil
    

parameterAtLength(_:from:)

Returns the curve parameter at the given arc-length distance from a starting parameter.

public func parameterAtLength(_ arcLength: Double, from fromParameter: Double? = nil) -> Double?

Use this to trim a curve to a specific arc length, or to place features at measured positions along a composite curve.

  • Parameters: arcLength — desired arc-length distance; may be negative to travel in reverse; fromParameter — starting parameter (defaults to domain.lowerBound).
  • Returns: Parameter value at the given arc-length offset, or nil if the computation fails.
  • OCCT: the accumulated GeomAbs_CN sub-piece lengths, with the final narrow piece handed to GCPnts_AbscissaPoint (via OCCTCurve2DParameterAtLength).
  • Note: Shares the subdivided measurement with length, so the two agree: curve.parameterAtLength(curve.length!) lands on domain.upperBound. OCCT’s own root finder inverts a single quadrature and would not (#603).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    if let u = seg.parameterAtLength(5) {
        let pt = seg.point(at: u)  // ≈ SIMD2(5, 0)
    }
    

Additional Arc Types

Curve2D.arcOfHyperbola(center:majorRadius:minorRadius:rotation:startAngle:endAngle:)

Creates a trimmed arc of a hyperbola.

public static func arcOfHyperbola(center: SIMD2<Double>, majorRadius: Double,
                                  minorRadius: Double, rotation: Double = 0,
                                  startAngle: Double, endAngle: Double) -> Curve2D?
  • Parameters: center — hyperbola centre; majorRadius — real semi-axis; minorRadius — imaginary semi-axis; rotation — major-axis rotation in radians (default 0); startAngle/endAngle — arc bounds in radians.
  • Returns: Hyperbolic arc, or nil on failure.
  • OCCT: GCE2d_MakeArcOfHyperbolaGeom2d_TrimmedCurve.
  • Example:
    let arc = Curve2D.arcOfHyperbola(center: .zero, majorRadius: 3, minorRadius: 2,
                                      startAngle: -1, endAngle: 1)
    

Curve2D.arcOfParabola(focus:direction:focalLength:startParam:endParam:)

Creates a trimmed arc of a parabola.

public static func arcOfParabola(focus: SIMD2<Double>, direction: SIMD2<Double>,
                                 focalLength: Double,
                                 startParam: Double, endParam: Double) -> Curve2D?
  • Parameters: focus — focus point; direction — axis direction; focalLength — focal distance (> 0); startParam/endParam — parameter range of the arc.
  • Returns: Parabolic arc, or nil on failure.
  • OCCT: GCE2d_MakeArcOfParabolaGeom2d_TrimmedCurve.
  • Example:
    let arc = Curve2D.arcOfParabola(focus: SIMD2(0, 1), direction: SIMD2(0, 1),
                                     focalLength: 1, startParam: -2, endParam: 2)
    

Conversion Extras

approximated(tolerance:continuity:maxSegments:maxDegree:)

Re-approximates this curve’s whole parameter domain as a BSpline, with a single scalar tolerance and explicit continuity control.

public func approximated(tolerance: Double = 1e-3, continuity: Int = 2,
                         maxSegments: Int = 100, maxDegree: Int = 8) -> Curve2D?

continuity maps to GeomAbs_Shape: 0=C0, 1=C1, 2=C2, 3=C3.

Distinct from approximatedInRange(first:last:toleranceU:toleranceV:maxDegree:maxSegments:) — a different OCCT algorithm, not a whole-domain shorthand for it. See #407.

  • Parameters: tolerance — maximum approximation error, applied over the whole curve; continuity — desired continuity order; maxSegments — maximum number of BSpline segments; maxDegree — maximum polynomial degree.
  • Returns: Approximated BSpline, or nil on failure.
  • OCCT: Geom2dConvert_ApproxCurve (via OCCTCurve2DApproximate).
  • Note: Defaults are shared with Curve3D.approximated and Surface.approximated (#406) — all three wrap the same GeomConvert_Approx*/Geom2dConvert_ApproxCurve family applied to a different OCCT geometry hierarchy, not independent algorithms that would justify independently-tuned numeric defaults.
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    let approx = circle.approximated(tolerance: 0.01, continuity: 2)
    

splitIndicesAtDiscontinuities(continuity:)

Finds knot indices where a BSpline has continuity discontinuities.

public func splitIndicesAtDiscontinuities(continuity: ParametricContinuity = .c1) -> [Int]?

Indices are 1-based into the curve’s own knot table, so bsplineKnot(index:) turns each one into a parameter. The first and last knots are always included, so a curve that never drops below continuity reports exactly those two.

  • Parameters: continuity: minimum continuity to require of each arc.
  • Returns: Array of knot indices where continuity drops below the requested level, or nil if not a BSpline or no discontinuities found.
  • OCCT: Geom2dConvert_BSplineCurveKnotSplitting (via OCCTCurve2DSplitAtDiscontinuities) — the sole wrapper of it, since #562 deleted the second pair (bsplineKnotSplits, bsplineKnotSplitValues) that also drove it.
  • Continuity range (#480): the continuity is a derivative order, and a knot splits only when degree - multiplicity < continuity, so the meaningful range is 0...degree and it saturates there. A cubic with simple interior knots is already C2 there, which means .c0, .c1 and .c2 all report just the two end knots and .c3 is the order that reports the interior ones.
  • All splits, however many (#562): this used to read a fixed 256 entries and take whatever came back, so a curve with more splits than that was cut off at 256 with nothing to notice it by. It now re-reads at the true count when the first pass came up short.
  • Example:
    if let bsp = Curve2D.bspline(poles: [...], knots: [...], multiplicities: [...], degree: 3) {
        let indices = bsp.splitIndicesAtDiscontinuities(continuity: .c3)
        let params = indices?.map { bsp.bsplineKnot(index: $0) }
    }
    

toArcsAndSegments(tolerance:angleTolerance:)

Approximates this curve as a sequence of arcs and line segments.

public func toArcsAndSegments(tolerance: Double = 0.01,
                              angleTolerance: Double = 0.04) -> [Curve2D]?

Useful for CNC G-code generation where only arcs and lines are supported.

  • Parameters: tolerance — maximum approximation error; angleTolerance — maximum angular deviation for arc fitting.
  • Returns: Array of arc/segment Curve2D objects, or nil on failure.
  • OCCT: Geom2dConvert_ApproxCurve arc-and-segment decomposition.
  • Example:
    let ellipse = Curve2D.ellipse(center: .zero, majorRadius: 10, minorRadius: 5)!
    if let arcs = ellipse.toArcsAndSegments(tolerance: 0.01) {
        // arcs suitable for G02/G03/G01 G-code output
    }
    

Conversion

toBSpline(tolerance:)

Converts this curve to an equivalent BSpline representation.

public func toBSpline(tolerance: Double = 1e-6) -> Curve2D?

Any analytic curve (line, circle, ellipse, arc) can be represented exactly as a rational BSpline. Required before using BSpline-specific query APIs.

  • Parameters: tolerance — conversion precision.
  • Returns: BSpline curve, or nil if conversion fails.
  • OCCT: Geom2dConvert::CurveToBSplineCurve(curve).
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 5)!
    if let bsp = circle.toBSpline() {
        print(bsp.poleCount!)  // NURBS representation of the circle
    }
    

toBezierSegments()

Splits a BSpline curve into its constituent Bezier segments.

public func toBezierSegments() -> [Curve2D]?
  • Returns: Array of Bezier segment curves, or nil if the curve is not a BSpline or decomposition fails.
  • OCCT: Geom2dConvert_BSplineCurveToBezierCurve::Arc(i).
  • Example:
    let bsp = Curve2D.interpolate(through: [SIMD2(0,0), SIMD2(3,4), SIMD2(6,0)])!
    if let segs = bsp.toBezierSegments() {
        print(segs.count)
    }
    

Curve2D.join(_:tolerance:)

Joins multiple curves into a single BSpline.

public static func join(_ curves: [Curve2D], tolerance: Double = 1e-6) -> Curve2D?

Each input curve is converted to BSpline form before concatenation. Curves must meet end-to-end within tolerance.

  • Parameters: curves — curves to join in order; tolerance — endpoint gap tolerance.
  • Returns: Joined BSpline, or nil if the array is empty or joining fails.
  • OCCT: Geom2dConvert_CompCurveToBSplineCurve (via OCCTCurve2DJoinToBSpline).
  • Example:
    let seg1 = Curve2D.segment(from: .zero, to: SIMD2(5, 0))!
    let seg2 = Curve2D.segment(from: SIMD2(5, 0), to: SIMD2(10, 5))!
    if let joined = Curve2D.join([seg1, seg2]) {
        print(joined.length!)
    }
    

Circle Construction

Methods on Curve2DGcc that construct circles satisfying geometric constraints. See the Curve2DGcc enum for the full solver; the entries below correspond to the // MARK: - Circle Construction section.

Curve2DGcc.circlesTangentTo(_:_:_:_:_:_:tolerance:)

Finds circles tangent to three curves.

public static func circlesTangentTo(
    _ c1: Curve2D, _ q1: Curve2DQualifier = .unqualified,
    _ c2: Curve2D, _ q2: Curve2DQualifier = .unqualified,
    _ c3: Curve2D, _ q3: Curve2DQualifier = .unqualified,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: c1/c2/c3 — input curves; q1/q2/q3 — qualifiers (.unqualified, .enclosing, .enclosed, .outside); tolerance — geometric tolerance.
  • Returns: Array of Curve2DCircleSolution values (each with center and radius); may be empty.
  • OCCT: Geom2dGcc_Circ2d3Tan.
  • Example:
    let c1 = Curve2D.circle(center: SIMD2(-5, 0), radius: 2)!
    let c2 = Curve2D.circle(center: SIMD2(5, 0), radius: 2)!
    let c3 = Curve2D.circle(center: SIMD2(0, 5), radius: 2)!
    let sols = Curve2DGcc.circlesTangentTo(c1, .outside, c2, .outside, c3, .outside)
    

Curve2DGcc.circlesTangentToTwoCurvesAndPoint(_:_:_:_:point:tolerance:)

Finds circles tangent to two curves and passing through a point.

public static func circlesTangentToTwoCurvesAndPoint(
    _ c1: Curve2D, _ q1: Curve2DQualifier = .unqualified,
    _ c2: Curve2D, _ q2: Curve2DQualifier = .unqualified,
    point: SIMD2<Double>,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: c1/c2 — input curves; q1/q2 — qualifiers; point — required pass-through point; tolerance — tolerance.
  • Returns: Array of solutions.
  • OCCT: Geom2dGcc_Circ2d2TanPt.
  • Example:
    let sols = Curve2DGcc.circlesTangentToTwoCurvesAndPoint(
        c1, .unqualified, c2, .unqualified, point: SIMD2(0, 0))
    

Curve2DGcc.circlesTangentWithCenter(_:_:center:tolerance:)

Finds circles tangent to a curve with a given center point.

public static func circlesTangentWithCenter(
    _ curve: Curve2D, _ qualifier: Curve2DQualifier = .unqualified,
    center: SIMD2<Double>,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: curve — input curve; qualifier — qualifier; center — desired circle centre; tolerance — tolerance.
  • Returns: Array of solutions.
  • OCCT: Geom2dGcc_Circ2dTanCen.
  • Example:
    let sols = Curve2DGcc.circlesTangentWithCenter(circle, .outside, center: SIMD2(10, 0))
    

Curve2DGcc.circlesTangentToTwoCurves(_:_:_:_:radius:tolerance:)

Finds circles tangent to two curves with a given radius.

public static func circlesTangentToTwoCurves(
    _ c1: Curve2D, _ q1: Curve2DQualifier = .unqualified,
    _ c2: Curve2D, _ q2: Curve2DQualifier = .unqualified,
    radius: Double,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: c1/c2 — input curves; q1/q2 — qualifiers; radius — required radius; tolerance — tolerance.
  • Returns: Array of solutions.
  • OCCT: Geom2dGcc_Circ2d2TanRad.
  • Example:
    let sols = Curve2DGcc.circlesTangentToTwoCurves(c1, .outside, c2, .outside, radius: 3)
    

Curve2DGcc.circlesTangentToPointWithRadius(_:_:point:radius:tolerance:)

Finds circles tangent to a curve, passing through a point, with a given radius.

public static func circlesTangentToPointWithRadius(
    _ curve: Curve2D, _ qualifier: Curve2DQualifier = .unqualified,
    point: SIMD2<Double>, radius: Double,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: curve — input curve; qualifier — qualifier; point — pass-through point; radius — required radius; tolerance — tolerance.
  • Returns: Array of solutions.
  • OCCT: Geom2dGcc_Circ2dTanPtRad.
  • Example:
    let sols = Curve2DGcc.circlesTangentToPointWithRadius(
        circle, .outside, point: SIMD2(0, 0), radius: 4)
    

Curve2DGcc.circlesThroughTwoPoints(_:_:radius:tolerance:)

Finds circles through two points with a given radius.

public static func circlesThroughTwoPoints(
    _ p1: SIMD2<Double>, _ p2: SIMD2<Double>,
    radius: Double,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: p1/p2 — required pass-through points; radius — required radius; tolerance — tolerance.
  • Returns: Array of solutions (0, 1, or 2).
  • OCCT: Geom2dGcc_Circ2d2PtRad.
  • Example:
    let sols = Curve2DGcc.circlesThroughTwoPoints(SIMD2(-3, 0), SIMD2(3, 0), radius: 5)
    

Curve2DGcc.circleThroughThreePoints(_:_:_:tolerance:)

Finds the circle through three points.

public static func circleThroughThreePoints(
    _ p1: SIMD2<Double>, _ p2: SIMD2<Double>, _ p3: SIMD2<Double>,
    tolerance: Double = 1e-6
) -> [Curve2DCircleSolution]
  • Parameters: p1/p2/p3 — three points; tolerance — coincidence tolerance.
  • Returns: Array with one solution, or empty if collinear.
  • OCCT: Geom2dGcc_Circ2d3Pt.
  • Example:
    let sols = Curve2DGcc.circleThroughThreePoints(
        SIMD2(5, 0), SIMD2(0, 5), SIMD2(-5, 0))
    

Line Construction

Methods on Curve2DGcc that construct lines satisfying geometric constraints. Corresponds to // MARK: - Line Construction.

Curve2DGcc.linesTangentTo(_:_:_:_:tolerance:)

Finds lines tangent to two curves.

public static func linesTangentTo(
    _ c1: Curve2D, _ q1: Curve2DQualifier = .unqualified,
    _ c2: Curve2D, _ q2: Curve2DQualifier = .unqualified,
    tolerance: Double = 1e-6
) -> [Curve2DLineSolution]
  • Parameters: c1/c2 — input curves; q1/q2 — qualifiers; tolerance — tolerance.
  • Returns: Array of Curve2DLineSolution values (each with a point on the line and direction).
  • OCCT: Geom2dGcc_Lin2d2Tan.
  • Example:
    let c1 = Curve2D.circle(center: SIMD2(-5, 0), radius: 2)!
    let c2 = Curve2D.circle(center: SIMD2(5, 0), radius: 2)!
    let lines = Curve2DGcc.linesTangentTo(c1, .outside, c2, .outside)
    

Curve2DGcc.linesTangentToPoint(_:_:point:tolerance:)

Finds lines tangent to a curve and passing through a point.

public static func linesTangentToPoint(
    _ curve: Curve2D, _ qualifier: Curve2DQualifier = .unqualified,
    point: SIMD2<Double>,
    tolerance: Double = 1e-6
) -> [Curve2DLineSolution]
  • Parameters: curve — input curve; qualifier — qualifier; point — pass-through point; tolerance — tolerance.
  • Returns: Array of line solutions.
  • OCCT: Geom2dGcc_Lin2dTanPt.
  • Example:
    let circle = Curve2D.circle(center: .zero, radius: 3)!
    let lines = Curve2DGcc.linesTangentToPoint(circle, .outside, point: SIMD2(10, 0))
    

Curve2D Transform (v0.128.0)

In-place mutation methods that modify the curve handle directly, unlike translated(by:) / rotated(around:…) which return new copies.

TransformType2D

Enum encoding the type of in-place 2D transform.

public enum TransformType2D: Int32, Sendable {
    case translation = 0
    case rotation = 1
    case scale = 2
    case mirrorPoint = 3
    case mirrorAxis = 4
}

Used internally by the in-place transform methods below.


translate(dx:dy:)

Translates the curve in place by (dx, dy).

@discardableResult
public func translate(dx: Double, dy: Double) -> Bool
  • Parameters: dx, dy — displacement components.
  • Returns: true on success.
  • OCCT: Geom2d_Curve::Translate(gp_Vec2d) (in-place, via OCCTCurve2DTransform).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(10, 0))!
    seg.translate(dx: 0, dy: 5)
    print(seg.startPoint)  // SIMD2(0, 5)
    

rotate(center:angle:)

Rotates the curve in place around a centre point.

@discardableResult
public func rotate(center: SIMD2<Double>, angle: Double) -> Bool
  • Parameters: center — rotation centre; angle — rotation angle in radians.
  • Returns: true on success.
  • OCCT: Geom2d_Curve::Rotate(gp_Pnt2d, angle) (in-place).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(1, 0), to: SIMD2(10, 0))!
    seg.rotate(center: .zero, angle: .pi / 2)
    

scale(center:factor:)

Scales the curve in place from a centre point.

@discardableResult
public func scale(center: SIMD2<Double>, factor: Double) -> Bool
  • Parameters: center — fixed point of scaling; factor — scale factor.
  • Returns: true on success.
  • OCCT: Geom2d_Curve::Scale(gp_Pnt2d, factor) (in-place).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(5, 0))!
    seg.scale(center: .zero, factor: 2)
    print(seg.length!)  // 10.0
    

mirrorPoint(_:)

Mirrors the curve in place through a point.

@discardableResult
public func mirrorPoint(_ point: SIMD2<Double>) -> Bool
  • Parameters: point — point of symmetry.
  • Returns: true on success.
  • OCCT: Geom2d_Curve::Mirror(gp_Pnt2d) (in-place).
  • Example:
    let seg = Curve2D.segment(from: .zero, to: SIMD2(4, 0))!
    seg.mirrorPoint(SIMD2(2, 0))
    

mirrorAxis(origin:direction:)

Mirrors the curve in place through an axis.

@discardableResult
public func mirrorAxis(origin: SIMD2<Double>, direction: SIMD2<Double>) -> Bool
  • Parameters: origin — a point on the mirror axis; direction — axis direction.
  • Returns: true on success.
  • OCCT: Geom2d_Curve::Mirror(gp_Ax2d) (in-place).
  • Example:
    let seg = Curve2D.segment(from: SIMD2(0, 2), to: SIMD2(10, 2))!
    seg.mirrorAxis(origin: .zero, direction: SIMD2(1, 0))
    

Geom2dEval TBezier / AHTBezier Curves (v0.131.0)

Curve2D.tBezier(poles:alpha:)

Creates a 2D Trigonometric Bezier curve.

public static func tBezier(poles: [SIMD2<Double>], alpha: Double) -> Curve2D?

Uses a trigonometric Bernstein-like basis {1, sin(α·t), cos(α·t), …}. Parameter domain is [0, π/α]. Can represent circular arcs exactly without rational weights.

  • Parameters: poles — 2D control points (count must be odd and ≥ 3); alpha — frequency parameter (must be > 0).
  • Returns: TBezier curve, or nil if poles.count < 3, count is even, or alpha ≤ 0.
  • OCCT: OCCTGeom2dEvalTBezierCurveCreate.
  • Example:
    let poles: [SIMD2<Double>] = [SIMD2(1, 0), SIMD2(0, 1), SIMD2(-1, 0)]
    if let tb = Curve2D.tBezier(poles: poles, alpha: 1.0) {
        let pts = tb.drawAdaptive()
    }
    

Curve2D.ahtBezier(poles:algDegree:alpha:beta:)

Creates a 2D Algebraic-Hyperbolic-Trigonometric (AHT) Bezier curve.

public static func ahtBezier(poles: [SIMD2<Double>], algDegree: Int, alpha: Double, beta: Double) -> Curve2D?

Uses a mixed basis: {1, t, …, t^k, sinh(α·t), cosh(α·t), sin(β·t), cos(β·t)}. The number of poles must equal algDegree + 1 + 2*(alpha>0) + 2*(beta>0). Parameter range is [0, 1].

  • Parameters: poles — 2D control points; algDegree — algebraic polynomial degree (≥ 0); alpha — hyperbolic frequency (≥ 0; 0 omits hyperbolic terms); beta — trigonometric frequency (≥ 0; 0 omits trig terms).
  • Returns: AHT Bezier curve, or nil if the pole count is wrong or construction fails.
  • OCCT: OCCTGeom2dEvalAHTBezierCurveCreate.
  • Example:
    // Degree-2 algebraic + trig: needs 3 + 0 + 2 = 5 poles
    let poles: [SIMD2<Double>] = [
        SIMD2(0, 0), SIMD2(2, 1), SIMD2(4, 0),
        SIMD2(6, 1), SIMD2(8, 0)
    ]
    let aht = Curve2D.ahtBezier(poles: poles, algDegree: 2, alpha: 0, beta: .pi)
    

v0.51.0: GC_MakeLine2d variants

Curve2D.lineThroughPoints(_:_:)

Creates a 2D infinite line passing through two points.

public static func lineThroughPoints(_ p1: SIMD2<Double>, _ p2: SIMD2<Double>) -> Curve2D?

Unlike segment(from:to:) which creates a finite segment, this creates an infinite line through the two points.

  • Parameters: p1 — first point on the line; p2 — second point on the line.
  • Returns: 2D infinite line, or nil if points coincide.
  • OCCT: GC_MakeLine2d(p1, p2) (via OCCTCurve2DMakeLineThroughPoints).
  • Example:
    let line = Curve2D.lineThroughPoints(SIMD2(0, 0), SIMD2(5, 3))
    

Curve2D.lineParallel(point:direction:distance:)

Creates a 2D line parallel to a reference line at a given signed offset.

public static func lineParallel(
    point: SIMD2<Double>, direction: SIMD2<Double>, distance: Double
) -> Curve2D?

Positive distance offsets to the left of the direction.

  • Parameters: point — a point on the reference line; direction — reference line direction; distance — signed offset distance.
  • Returns: 2D infinite line, or nil on failure.
  • OCCT: GC_MakeLine2d parallel variant (via OCCTCurve2DMakeLineParallel).
  • Example:
    let line = Curve2D.lineParallel(
        point: .zero, direction: SIMD2(1, 0), distance: 5)
    // Creates y = 5 (5 units above the X axis)