Skip to content

EllipticalArc

EllipticalArc (from scenerystack/kite) is a Segment that generalizes Arc to ellipses: instead of a single radius, it has independent radiusX/radiusY, plus a rotation for the ellipse's semi-major axis. It's what shape.ellipticalArc( centerX, centerY, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise ) appends to the current subpath, and it's also what Arc.transformed() produces when a circular arc is transformed by a non-uniform scale (circles don't stay circular once x and y are scaled differently).

ts
import { EllipticalArc, Shape } from 'scenerystack/kite';
import { Vector2 } from 'scenerystack/dot';

const halfEllipse = new EllipticalArc( new Vector2( 0, 0 ), 80, 40, 0, 0, Math.PI, false );
halfEllipse.start;   // Vector2( 80, 0 )
halfEllipse.bounds;  // Bounds2 tightly containing the swept arc

// The usual way you'll get one: build it through Shape
const shape = new Shape().ellipticalArc( 0, 0, 80, 40, 0, 0, Math.PI, false );

A circular Arc is just an EllipticalArc with radiusX === radiusY and rotation === 0

kite keeps them as separate classes for efficiency (circular math is cheaper), not because they're conceptually different — if you're writing code generic over "some kind of arc segment," EllipticalArc is the superset. Internally, EllipticalArc computes a unitTransform (a Transform3 mapping the ellipse to a unit circle) and delegates position/tangent queries to the equivalent Arc on that unit circle, exposed as unitArcSegment.

Constructor

ts
new EllipticalArc(
  center: Vector2,
  radiusX: number,
  radiusY: number,
  rotation: number,
  startAngle: number,
  endAngle: number,
  anticlockwise: boolean
)

rotation (radians) rotates the whole ellipse — including which direction counts as radiusX vs radiusY — around center, applied before startAngle/endAngle are measured.

Public API

MemberDescription
center, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwiseThe defining values, each with a getter and setter (setters recompute cached bounds/tangents)
start / endThe endpoint Vector2s
startTangent / endTangentNormalized tangent direction at each endpoint
actualEndAngleendAngle remapped relative to startAngle to reflect the true angular sweep
angleDifferenceThe signed angular sweep, accounting for anticlockwise
isFullPerimetertrue if the arc sweeps a complete ellipse
unitTransformThe Transform3 mapping this ellipse to/from a unit circle
unitArcSegmentThe equivalent circular Arc on that unit circle
boundsThe tight Bounds2 around the swept arc
positionAtAngle( angle ) / tangentAtAngle( angle )Position/tangent at a raw angle, rather than a parametric t
transformed( matrix )Always returns another EllipticalArc (unlike Arc.transformed(), which can stay circular)
reversed()A new EllipticalArc tracing the same points in the opposite direction

EllipticalArc also implements the shared Segment contract — positionAt( t ), tangentAt( t ), curvatureAt( t ), subdivided( t ), getArcLength() — the same as Arc, Line, Quadratic, and Cubic.

  • Shape — the fluent ellipticalArc() builder and static Shape.ellipse() factory.
  • Arc — the circular special case, and what a uniformly-scaled EllipticalArc.transformed() conceptually mirrors.