Skip to content

Segment

Under Construction

This documentation is auto-generated, and is a work in progress. Please see the source code at https://github.com/phetsims/kite/blob/main/js/segments/Segment.ts for the most up-to-date information.

Overview

A segment represents a specific curve with a start and end.

Each segment is treated parametrically, where t=0 is the start of the segment, and t=1 is the end. Values of t between those represent points along the segment.

@author Jonathan Olson <jonathan.olson@colorado.edu> /* global paper */

Class Segment

import { Segment } from 'scenerystack/kite';

Constructor

new Segment()

Instance Methods

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1. NOTE that this function doesn't keep a constant magnitude tangent.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

curvatureAt( t : number ) : number

Returns the signed curvature (positive for visual clockwise - mathematical counterclockwise)

subdivided( t : number ) : Segment[]

Returns an array with up to 2 sub-segments, split at the parametric t value. The segments together should make the same shape as the original segment.

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first

strokeLeft( lineWidth : number ) : Segment[]

Returns an array of segments that will draw an offset curve on the logical left side

strokeRight( lineWidth : number ) : Segment[]

Returns an array of segments that will draw an offset curve on the logical right side

windingIntersection( ray : Ray2 ) : number

Returns the winding number for intersection with a ray

getInteriorExtremaTs() : number[]

Returns a list of t values where dx/dt or dy/dt is 0 where 0 < t < 1. subdividing on these will result in monotonic segments

intersection( ray : Ray2 ) : RayIntersection[]

Returns a list of intersections between the segment and the ray.

getBounds() : Bounds2

Returns a {Bounds2} representing the bounding box for the segment.

getSignedAreaFragment() : number

Returns signed area contribution for this segment using Green's Theorem

getNondegenerateSegments() : Segment[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

getOverlaps( segment : Segment, epsilon? : number ) : Overlap[] | null

writeToContext( context : CanvasRenderingContext2D )

Draws the segment to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : Segment

Returns a new segment that represents this segment after transformation by the matrix

reversed() : Segment

invalidate()

serialize() : SerializedSegment

areStrokedBoundsDilated() : boolean

Will return true if the start/end tangents are purely vertical or horizontal. If all of the segments of a shape have this property, then the only line joins will be a multiple of pi/2 (90 degrees), and so all of the types of line joins will have the same bounds. This means that the stroked bounds will just be a pure dilation of the regular bounds, by lineWidth / 2.

getBoundsWithTransform( matrix : Matrix3 ) : Bounds2

TODO: override everywhere so this isn't necessary (it's not particularly efficient!) https://github.com/phetsims/kite/issues/76

slice( t0 : number, t1 : number ) : Segment

Extracts a slice of a segment, based on the parametric value.

Given that this segment is represented by the interval [0,1]

subdivisions( tList : number[] ) : Segment[]

@param tList - list of sorted t values from 0 <= t <= 1

subdividedIntoMonotone() : Segment[]

Return an array of segments from breaking this segment into monotone pieces

isSufficientlyFlat( distanceEpsilon : number, curveEpsilon : number ) : boolean

Determines if the segment is sufficiently flat (given certain epsilon values)

@param distanceEpsilon - controls level of subdivision by attempting to ensure a maximum (squared) deviation from the curve @param curveEpsilon - controls level of subdivision by attempting to ensure a maximum curvature change between segments

getArcLength( distanceEpsilon? : number, curveEpsilon? : number, maxLevels? : number ) : number

Returns the (sometimes approximate) arc length of the segment.

getDashValues( lineDash : number[], lineDashOffset : number, distanceEpsilon : number, curveEpsilon : number ) : DashValues

Returns information about the line dash parametric offsets for a given segment.

As always, this is fairly approximate depending on the type of segment.

@param lineDash @param lineDashOffset @param distanceEpsilon - controls level of subdivision by attempting to ensure a maximum (squared) deviation from the curve @param curveEpsilon - controls level of subdivision by attempting to ensure a maximum curvature change between segments

toPiecewiseLinearSegments( options : PiecewiseLinearOptions, minLevels? : number, maxLevels? : number, segments? : Line[], start? : Vector2, end? : Vector2 ) : Line[]

@param [options] @param [minLevels] - how many levels to force subdivisions @param [maxLevels] - prevent subdivision past this level @param [segments] @param [start] @param [end]

toPiecewiseLinearOrArcSegments( providedOptions : PiecewiseLinearOrArcOptions ) : Segment[]

Returns a list of Line and/or Arc segments that approximates this segment.

getClosestPoints( point : Vector2 ) : ClosestToPointResult[]

Instance Properties

invalidationEmitter : TEmitter

Static Methods

closestToPoint( segments : Segment[], point : Vector2, threshold : number ) : ClosestToPointResult[]

List of results (since there can be duplicates), threshold is used for subdivision, where it will exit if all of the segments are shorter than the threshold

TODO: solve segments to determine this analytically! https://github.com/phetsims/kite/issues/76

polynomialGetOverlapCubic( p0s : number, p1s : number, p2s : number, p3s : number, q0s : number, q1s : number, q2s : number, q3s : number ) : PossibleSimpleOverlap

Given the cubic-premultiplied values for two cubic bezier curves, determines (if available) a specified (a,b) pair such that p( t ) === q( a * t + b ).

Given a 1-dimensional cubic bezier determined by the control points p0, p1, p2 and p3, compute:

[ p0s ] [ 1 0 0 0 ] [ p0 ] [ p1s ] == [ -3 3 0 0 ] * [ p1 ] [ p2s ] == [ 3 -6 3 0 ] * [ p2 ] [ p3s ] [ -1 3 -3 1 ] [ p3 ]

see Cubic.getOverlaps for more information.

polynomialGetOverlapQuadratic( p0s : number, p1s : number, p2s : number, q0s : number, q1s : number, q2s : number ) : PossibleSimpleOverlap

Given the quadratic-premultiplied values for two quadratic bezier curves, determines (if available) a specified (a,b) pair such that p( t ) === q( a * t + b ).

Given a 1-dimensional quadratic bezier determined by the control points p0, p1, p2, compute:

[ p0s ] [ 1 0 0 ] [ p0 ] [ p1s ] == [ -2 2 0 ] * [ p1 ] [ p2s ] [ 2 -2 3 ] * [ p2 ]

see Quadratic.getOverlaps for more information.

polynomialGetOverlapLinear( p0s : number, p1s : number, q0s : number, q1s : number ) : PossibleSimpleOverlap

Given the linear-premultiplied values for two lines, determines (if available) a specified (a,b) pair such that p( t ) === q( a * t + b ).

Given a line determined by the control points p0, p1, compute:

[ p0s ] == [ 1 0 ] * [ p0 ] [ p1s ] == [ -1 1 ] * [ p1 ]

see Quadratic/Cubic.getOverlaps for more information.

intersect( a : Segment, b : Segment ) : SegmentIntersection[]

Returns all the distinct (non-endpoint, non-finite) intersections between the two segments.

deserialize( obj : SerializedSegment ) : Segment

Returns a Segment from the serialized representation.

isSufficientlyFlat( distanceEpsilon : number, curveEpsilon : number, start : Vector2, middle : Vector2, end : Vector2 ) : boolean

Determines if the start/middle/end points are representative of a sufficiently flat segment (given certain epsilon values)

@param start @param middle @param end @param distanceEpsilon - controls level of subdivision by attempting to ensure a maximum (squared) deviation from the curve @param curveEpsilon - controls level of subdivision by attempting to ensure a maximum curvature change between segments

filterClosestToPointResult( results : ClosestToPointResult[] ) : ClosestToPointResult[]

Class Arc

A circular arc (a continuous sub-part of a circle).

@author Jonathan Olson <jonathan.olson@colorado.edu>

import { Arc } from 'scenerystack/kite';

Constructor

new Arc( center : Vector2, radius : number, startAngle : number, endAngle : number, anticlockwise : boolean )

Instance Methods

setCenter( center : Vector2 ) : this

Sets the center of the Arc.

getCenter() : Vector2

Returns the center of this Arc.

setRadius( radius : number ) : this

Sets the radius of the Arc.

getRadius() : number

Returns the radius of this Arc.

setStartAngle( startAngle : number ) : this

Sets the startAngle of the Arc.

getStartAngle() : number

Returns the startAngle of this Arc.

setEndAngle( endAngle : number ) : this

Sets the endAngle of the Arc.

getEndAngle() : number

Returns the endAngle of this Arc.

setAnticlockwise( anticlockwise : boolean ) : this

Sets the anticlockwise of the Arc.

getAnticlockwise() : boolean

Returns the anticlockwise of this Arc.

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1.

NOTE: positionAt( 0 ) will return the start of the segment, and positionAt( 1 ) will return the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

NOTE: tangentAt( 0 ) will return the tangent at the start of the segment, and tangentAt( 1 ) will return the tangent at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

curvatureAt( t : number ) : number

Returns the signed curvature of the segment at the parametric value t, where 0 <= t <= 1.

The curvature will be positive for visual clockwise / mathematical counterclockwise curves, negative for opposite curvature, and 0 for no curvature.

NOTE: curvatureAt( 0 ) will return the curvature at the start of the segment, and curvatureAt( 1 ) will return the curvature at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

subdivided( t : number ) : Arc[]

Returns an array with up to 2 sub-segments, split at the parametric t value. Together (in order) they should make up the same shape as the current segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

invalidate()

Clears cached information, should be called when any of the 'constructor arguments' are mutated.

getStart() : Vector2

Gets the start position of this arc.

getEnd() : Vector2

Gets the end position of this arc.

getStartTangent() : Vector2

Gets the unit vector tangent to this arc at the start point.

getEndTangent() : Vector2

Gets the unit vector tangent to the arc at the end point.

getActualEndAngle() : number

Gets the end angle in radians.

getIsFullPerimeter() : boolean

Returns a boolean value that indicates if the arc wraps up by more than two Pi.

getAngleDifference() : number

Returns an angle difference that represents how "much" of the circle our arc covers.

The answer is always greater or equal to zero The answer can exceed two Pi

getBounds() : Bounds2

Returns the bounds of this segment.

getNondegenerateSegments() : Arc[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

mapAngle( angle : number ) : number

Maps a contained angle to between [startAngle,actualEndAngle), even if the end angle is lower.

tAtAngle( angle : number ) : number

Returns the parametrized value t for a given angle. The value t should range from 0 to 1 (inclusive).

angleAt( t : number ) : number

Returns the angle for the parametrized t value. The t value should range from 0 to 1 (inclusive).

positionAtAngle( angle : number ) : Vector2

Returns the position of this arc at angle.

tangentAtAngle( angle : number ) : Vector2

Returns the normalized tangent of this arc. The tangent points outward (inward) of this arc for clockwise (anticlockwise) direction.

containsAngle( angle : number ) : boolean

Returns whether the given angle is contained by the arc (whether a ray from the arc's origin going in that angle will intersect the arc).

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first

strokeLeft( lineWidth : number ) : Arc[]

Returns an array of arcs that will draw an offset on the logical left side

strokeRight( lineWidth : number ) : Arc[]

Returns an array of arcs that will draw an offset curve on the logical right side

getInteriorExtremaTs() : number[]

Returns a list of t values where dx/dt or dy/dt is 0 where 0 < t < 1. subdividing on these will result in monotonic segments Does not include t=0 and t=1

intersection( ray : Ray2 ) : RayIntersection[]

Hit-tests this segment with the ray. An array of all intersections of the ray with this segment will be returned. For details, see the documentation in Segment.js

windingIntersection( ray : Ray2 ) : number

Returns the resultant winding number of this ray intersecting this arc.

writeToContext( context : CanvasRenderingContext2D )

Draws this arc to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : Arc | EllipticalArc

Returns a new copy of this arc, transformed by the given matrix.

TODO: test various transform types, especially rotations, scaling, shears, etc. https://github.com/phetsims/kite/issues/76

getSignedAreaFragment() : number

Returns the contribution to the signed area computed using Green's Theorem, with P=-y/2 and Q=x/2.

NOTE: This is this segment's contribution to the line integral (-y/2 dx + x/2 dy).

reversed() : Arc

Returns a reversed copy of this segment (mapping the parametrization from [0,1] => [1,0]).

getArcLength() : number

Returns the arc length of the segment.

toPiecewiseLinearOrArcSegments() : Segment[]

We can handle this simply by returning ourselves.

serialize() : SerializedArc

Returns an object form that can be turned back into a segment with the corresponding deserialize method.

getOverlaps( segment : Segment, epsilon ) : Overlap[] | null

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param segment @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

getConicMatrix() : Matrix3

Returns the matrix representation of the conic section of the circle. See https://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections

Static Methods

deserialize( obj : SerializedArc ) : Arc

Returns an Arc from the serialized representation.

computeActualEndAngle( startAngle : number, endAngle : number, anticlockwise : boolean ) : number

Determines the actual end angle (compared to the start angle).

Normalizes the sign of the angles, so that the sign of ( endAngle - startAngle ) matches whether it is anticlockwise.

getAngularOverlaps( startAngle1 : number, endAngle1 : number, startAngle2 : number, endAngle2 : number ) : Overlap[]

Determine whether two Arcs overlap over continuous sections, and if so finds the a,b pairs such that p( t ) === q( a * t + b ).

@param startAngle1 - Start angle of arc 1 @param endAngle1 - "Actual" end angle of arc 1 @param startAngle2 - Start angle of arc 2 @param endAngle2 - "Actual" end angle of arc 2 @returns - Any overlaps (from 0 to 2)

getOverlaps( arc1 : Arc, arc2 : Arc ) : Overlap[]

Determine whether two Arcs overlap over continuous sections, and if so finds the a,b pairs such that p( t ) === q( a * t + b ).

@returns - Any overlaps (from 0 to 2)

getCircleIntersectionPoint( center1 : Vector2, radius1 : number, center2 : Vector2, radius2 : number ) : Vector2[]

Returns the points of intersections between two circles.

@param center1 - Center of the first circle @param radius1 - Radius of the first circle @param center2 - Center of the second circle @param radius2 - Radius of the second circle

intersect( a : Arc, b : Arc ) : SegmentIntersection[]

Returns any (finite) intersection between the two arc segments.

createFromPoints( startPoint : Vector2, middlePoint : Vector2, endPoint : Vector2 ) : Segment

Creates an Arc (or if straight enough a Line) segment that goes from the startPoint to the endPoint, touching the middlePoint somewhere between the two.

Type ClosestToPointResult

import type { ClosestToPointResult } from 'scenerystack/kite';
  • segment: Segment
  • t: number
  • closestPoint: Vector2
  • distanceSquared: number

Class Cubic

Cubic Bezier segment.

See http://www.cis.usouthal.edu/~hain/general/Publications/Bezier/BezierFlattening.pdf for info

Good reference: http://cagd.cs.byu.edu/~557/text/ch2.pdf

@author Jonathan Olson <jonathan.olson@colorado.edu>

import { Cubic } from 'scenerystack/kite';

Constructor

new Cubic( start : Vector2, control1 : Vector2, control2 : Vector2, end : Vector2 )

Instance Methods

setStart( start : Vector2 ) : this

Sets the start point of the Cubic.

getStart() : Vector2

Returns the start of this Cubic.

setControl1( control1 : Vector2 ) : this

Sets the first control point of the Cubic.

getControl1() : Vector2

Returns the first control point of this Cubic.

setControl2( control2 : Vector2 ) : this

Sets the second control point of the Cubic.

getControl2() : Vector2

Returns the second control point of this Cubic.

setEnd( end : Vector2 ) : this

Sets the end point of the Cubic.

getEnd() : Vector2

Returns the end of this Cubic.

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1.

NOTE: positionAt( 0 ) will return the start of the segment, and positionAt( 1 ) will return the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

NOTE: tangentAt( 0 ) will return the tangent at the start of the segment, and tangentAt( 1 ) will return the tangent at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

curvatureAt( t : number ) : number

Returns the signed curvature of the segment at the parametric value t, where 0 <= t <= 1.

The curvature will be positive for visual clockwise / mathematical counterclockwise curves, negative for opposite curvature, and 0 for no curvature.

NOTE: curvatureAt( 0 ) will return the curvature at the start of the segment, and curvatureAt( 1 ) will return the curvature at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

subdivided( t : number ) : Cubic[]

Returns an array with up to 2 sub-segments, split at the parametric t value. Together (in order) they should make up the same shape as the current segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

invalidate()

Clears cached information, should be called when any of the 'constructor arguments' are mutated.

getStartTangent() : Vector2

Gets the start position of this cubic polynomial.

getEndTangent() : Vector2

Gets the end position of this cubic polynomial.

getR() : Vector2

TODO: documentation https://github.com/phetsims/kite/issues/76

getS() : Vector2

TODO: documentation https://github.com/phetsims/kite/issues/76

getTCusp() : number

Returns the parametric t value for the possible cusp location. A cusp may or may not exist at that point.

getTDeterminant() : number

Returns the determinant value for the cusp, which indicates the presence (or lack of presence) of a cusp.

getTInflection1() : number

Returns the parametric t value for the potential location of the first possible inflection point.

getTInflection2() : number

Returns the parametric t value for the potential location of the second possible inflection point.

getQuadratics() : Quadratic[] | null

If there is a cusp, this cubic will consist of one or two quadratic segments, typically "start => cusp" and "cusp => end".

getXExtremaT() : number[]

Returns a list of parametric t values where x-extrema exist, i.e. where dx/dt==0. These are candidate locations on the cubic for "maximum X" and "minimum X", and are needed for bounds computations.

getYExtremaT() : number[]

Returns a list of parametric t values where y-extrema exist, i.e. where dy/dt==0. These are candidate locations on the cubic for "maximum Y" and "minimum Y", and are needed for bounds computations.

getBounds() : Bounds2

Returns the bounds of this segment.

getNondegenerateSegments() : Segment[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

hasCusp() : boolean

Returns whether this cubic has a cusp.

toRS( point : Vector2 ) : Vector2

offsetTo( r : number, reverse : boolean ) : Line[]

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first

strokeLeft( lineWidth : number ) : Line[]

Returns an array of lines that will draw an offset curve on the logical left side

strokeRight( lineWidth : number ) : Line[]

Returns an array of lines that will draw an offset curve on the logical right side

getInteriorExtremaTs() : number[]

Returns a list of t values where dx/dt or dy/dt is 0 where 0 < t < 1. subdividing on these will result in monotonic segments The list does not include t=0 and t=1

intersection( ray : Ray2 ) : RayIntersection[]

Hit-tests this segment with the ray. An array of all intersections of the ray with this segment will be returned. For details, see the documentation in Segment.js

windingIntersection( ray : Ray2 ) : number

Returns the winding number for intersection with a ray

writeToContext( context : CanvasRenderingContext2D )

Draws the segment to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : Cubic

Returns a new cubic that represents this cubic after transformation by the matrix

degreeReduced( epsilon : number ) : Quadratic | null

Returns a degree-reduced quadratic Bezier if possible, otherwise it returns null

getSignedAreaFragment() : number

Returns the contribution to the signed area computed using Green's Theorem, with P=-y/2 and Q=x/2.

NOTE: This is this segment's contribution to the line integral (-y/2 dx + x/2 dy).

reversed() : Cubic

Returns a reversed copy of this segment (mapping the parametrization from [0,1] => [1,0]).

getSelfIntersection() : SegmentIntersection | null

If it exists, returns the point where the cubic curve self-intersects.

@returns - Null if there is no intersection

serialize() : SerializedCubic

Returns an object form that can be turned back into a segment with the corresponding deserialize method.

getOverlaps( segment : Segment, epsilon ) : Overlap[] | null

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param segment @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

Instance Properties

degree : number

Degree of this polynomial (cubic)

Static Methods

deserialize( obj : SerializedCubic ) : Cubic

Returns a Cubic from the serialized representation.

extremaT( v0 : number, v1 : number, v2 : number, v3 : number ) : number[]

Finds what t values the cubic extrema are at (if any). This is just the 1-dimensional case, used for multiple purposes

getOverlaps( cubic1 : Cubic, cubic2 : Cubic, epsilon ) : Overlap[]

Determine whether two Cubics overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

NOTE: for this particular function, we assume we're not degenerate. Things may work if we can be degree-reduced to a quadratic, but generally that shouldn't be done.

@param cubic1 @param cubic2 @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

Type DashValues

import type { DashValues } from 'scenerystack/kite';
  • values: number[]
    Parametric (t) values for where dash boundaries exist
  • arcLength: number
    Total arc length for this segment
  • initiallyInside: boolean
    Whether the start of the segment is inside a dash (instead of a gap)

Class EllipticalArc

An elliptical arc (a continuous sub-part of an ellipse).

Additional helpful notes: - http://www.w3.org/TR/SVG/implnote.html#PathElementImplementationNotes - http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-ellipse (note: context.ellipse was removed from the Canvas spec)

@author Jonathan Olson <jonathan.olson@colorado.edu>

import { EllipticalArc } from 'scenerystack/kite';

Constructor

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

Instance Methods

setCenter( center : Vector2 ) : this

Sets the center of the EllipticalArc.

getCenter() : Vector2

Returns the center of this EllipticalArc.

setRadiusX( radiusX : number ) : this

Sets the semi-major radius of the EllipticalArc.

getRadiusX() : number

Returns the semi-major radius of this EllipticalArc.

setRadiusY( radiusY : number ) : this

Sets the semi-minor radius of the EllipticalArc.

getRadiusY() : number

Returns the semi-minor radius of this EllipticalArc.

setRotation( rotation : number ) : this

Sets the rotation of the EllipticalArc.

getRotation() : number

Returns the rotation of this EllipticalArc.

setStartAngle( startAngle : number ) : this

Sets the startAngle of the EllipticalArc.

getStartAngle() : number

Returns the startAngle of this EllipticalArc.

setEndAngle( endAngle : number ) : this

Sets the endAngle of the EllipticalArc.

getEndAngle() : number

Returns the endAngle of this EllipticalArc.

setAnticlockwise( anticlockwise : boolean ) : this

Sets the anticlockwise of the EllipticalArc.

getAnticlockwise() : boolean

Returns the anticlockwise of this EllipticalArc.

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1.

NOTE: positionAt( 0 ) will return the start of the segment, and positionAt( 1 ) will return the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

NOTE: tangentAt( 0 ) will return the tangent at the start of the segment, and tangentAt( 1 ) will return the tangent at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

curvatureAt( t : number ) : number

Returns the signed curvature of the segment at the parametric value t, where 0 <= t <= 1.

The curvature will be positive for visual clockwise / mathematical counterclockwise curves, negative for opposite curvature, and 0 for no curvature.

NOTE: curvatureAt( 0 ) will return the curvature at the start of the segment, and curvatureAt( 1 ) will return the curvature at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

subdivided( t : number ) : EllipticalArc[]

Returns an array with up to 2 sub-segments, split at the parametric t value. Together (in order) they should make up the same shape as the current segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

invalidate()

Clears cached information, should be called when any of the 'constructor arguments' are mutated.

getUnitTransform() : Transform3

Computes a transform that maps a unit circle into this ellipse's location.

Helpful, since we can get the parametric position of our unit circle (at t), and then transform it with this transform to get the ellipse's parametric position (at t).

getStart() : Vector2

Gets the start point of this ellipticalArc

getEnd() : Vector2

Gets the end point of this ellipticalArc

getStartTangent() : Vector2

Gets the tangent vector (normalized) to this ellipticalArc at the start, pointing in the direction of motion (from start to end)

getEndTangent() : Vector2

Gets the tangent vector (normalized) to this ellipticalArc at the end point, pointing in the direction of motion (from start to end)

getActualEndAngle() : number

Gets the end angle in radians

getIsFullPerimeter() : boolean

Returns a boolean value that indicates if the arc wraps up by more than two Pi

getAngleDifference() : number

Returns an angle difference that represents how "much" of the circle our arc covers

The answer is always greater or equal to zero The answer can exceed two Pi

getUnitArcSegment() : Arc

A unit arg segment that we can map to our ellipse. useful for hit testing and such.

getBounds() : Bounds2

Returns the bounds of this segment.

getNondegenerateSegments() : Segment[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

mapAngle( angle : number ) : number

Maps a contained angle to between [startAngle,actualEndAngle), even if the end angle is lower.

TODO: remove duplication with Arc https://github.com/phetsims/kite/issues/76

tAtAngle( angle : number ) : number

Returns the parametrized value t for a given angle. The value t should range from 0 to 1 (inclusive).

TODO: remove duplication with Arc https://github.com/phetsims/kite/issues/76

angleAt( t : number ) : number

Returns the angle for the parametrized t value. The t value should range from 0 to 1 (inclusive).

positionAtAngle( angle : number ) : Vector2

Returns the position of this arc at angle.

tangentAtAngle( angle : number ) : Vector2

Returns the normalized tangent of this arc. The tangent points outward (inward) of this arc for clockwise (anticlockwise) direction.

offsetTo( r : number, reverse : boolean ) : Line[]

Returns an array of straight lines that will draw an offset on the logical left (right) side for reverse false (true) It discretizes the elliptical arc in 32 segments and returns an offset curve as a list of lineTos/

@param r - distance @param reverse

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first.

strokeLeft( lineWidth : number ) : Line[]

Returns an array of straight lines that will draw an offset on the logical left side.

strokeRight( lineWidth : number ) : Line[]

Returns an array of straight lines that will draw an offset curve on the logical right side.

getInteriorExtremaTs() : number[]

Returns a list of t values where dx/dt or dy/dt is 0 where 0 < t < 1. subdividing on these will result in monotonic segments Does not include t=0 and t=1.

intersection( ray : Ray2 ) : RayIntersection[]

Hit-tests this segment with the ray. An array of all intersections of the ray with this segment will be returned. For details, see the documentation in Segment.js

windingIntersection( ray : Ray2 ) : number

Returns the resultant winding number of this ray intersecting this arc.

writeToContext( context : CanvasRenderingContext2D )

Draws this arc to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : EllipticalArc

Returns this elliptical arc transformed by a matrix

getSignedAreaFragment() : number

Returns the contribution to the signed area computed using Green's Theorem, with P=-y/2 and Q=x/2.

NOTE: This is this segment's contribution to the line integral (-y/2 dx + x/2 dy).

reversed() : EllipticalArc

Returns a reversed copy of this segment (mapping the parametrization from [0,1] => [1,0]).

serialize() : SerializedEllipticalArc

Returns an object form that can be turned back into a segment with the corresponding deserialize method.

getOverlaps( segment : Segment, epsilon ) : Overlap[] | null

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param segment @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

getConicMatrix() : Matrix3

Returns the matrix representation of the conic section of the ellipse. See https://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections

Static Methods

deserialize( obj : SerializedEllipticalArc ) : EllipticalArc

Returns an EllipticalArc from the serialized representation.

getOverlapType( a : EllipticalArc, b : EllipticalArc, epsilon ) : EllipticalArcOverlapType

Returns what type of overlap is possible based on the center/radii/rotation. We ignore the start/end angles and anticlockwise information, and determine if the FULL ellipses overlap.

getOverlaps( a : EllipticalArc, b : EllipticalArc ) : Overlap[]

Determine whether two elliptical arcs overlap over continuous sections, and if so finds the a,b pairs such that p( t ) === q( a * t + b ).

@returns - Any overlaps (from 0 to 2)

intersect( a : EllipticalArc, b : EllipticalArc, epsilon ) : SegmentIntersection[]

Returns any (finite) intersection between the two elliptical arc segments.

computeUnitMatrix( center : Vector2, radiusX : number, radiusY : number, rotation : number ) : Matrix3

Matrix that transforms the unit circle into our ellipse

computeUnitTransform( center : Vector2, radiusX : number, radiusY : number, rotation : number ) : Transform3

Transforms the unit circle into our ellipse.

adapted from http://www.w3.org/TR/SVG/implnote.html#PathElementImplementationNotes

Class EllipticalArcOverlapType

import { EllipticalArcOverlapType } from 'scenerystack/kite';

Static Properties

MATCHING_OVERLAP : EllipticalArcOverlapType

(readonly)

radiusX of one equals radiusX of the other, with equivalent centers and rotations to work

OPPOSITE_OVERLAP : EllipticalArcOverlapType

(readonly)

radiusX of one equals radiusY of the other, with equivalent centers and rotations to work

NONE : EllipticalArcOverlapType

(readonly)

no overlap

enumeration : Enumeration

(readonly)

Class KiteLine

A line segment (all points directly between the start and end point)

@author Jonathan Olson <jonathan.olson@colorado.edu>

import { KiteLine } from 'scenerystack/kite';

Constructor

new KiteLine( start : Vector2, end : Vector2 )

Instance Methods

setStart( start : Vector2 ) : this

Sets the start point of the Line.

getStart() : Vector2

Returns the start of this Line.

setEnd( end : Vector2 ) : this

Sets the end point of the Line.

getEnd() : Vector2

Returns the end of this Line.

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1.

NOTE: positionAt( 0 ) will return the start of the segment, and positionAt( 1 ) will return the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

NOTE: tangentAt( 0 ) will return the tangent at the start of the segment, and tangentAt( 1 ) will return the tangent at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

curvatureAt( t : number ) : number

Returns the signed curvature of the segment at the parametric value t, where 0 <= t <= 1.

The curvature will be positive for visual clockwise / mathematical counterclockwise curves, negative for opposite curvature, and 0 for no curvature.

NOTE: curvatureAt( 0 ) will return the curvature at the start of the segment, and curvatureAt( 1 ) will return the curvature at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

subdivided( t : number ) : Segment[]

Returns an array with up to 2 sub-segments, split at the parametric t value. Together (in order) they should make up the same shape as the current segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

invalidate()

Clears cached information, should be called when any of the 'constructor arguments' are mutated.

getStartTangent() : Vector2

Returns a normalized unit vector that is tangent to this line (at the starting point) the unit vectors points toward the end points.

getEndTangent() : Vector2

Returns the normalized unit vector that is tangent to this line same as getStartTangent, since this is a straight line

getBounds() : Bounds2

Returns the bounds of this segment.

getBoundsWithTransform( matrix : Matrix3 ) : Bounds2

Returns the bounding box for this transformed Line

getNondegenerateSegments() : Segment[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first

strokeLeft( lineWidth : number ) : Line[]

Returns an array of Line that will draw an offset curve on the logical left side

strokeRight( lineWidth : number ) : Line[]

Returns an array of Line that will draw an offset curve on the logical right side

getInteriorExtremaTs() : number[]

In general, this method returns a list of t values where dx/dt or dy/dt is 0 where 0 < t < 1. subdividing on these will result in monotonic segments Since lines are already monotone, it returns an empty array.

intersection( ray : Ray2 ) : RayIntersection[]

Hit-tests this segment with the ray. An array of all intersections of the ray with this segment will be returned. For details, see the documentation in Segment.js

windingIntersection( ray : Ray2 ) : number

Returns the resultant winding number of a ray intersecting this line.

writeToContext( context : CanvasRenderingContext2D )

Draws this line to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : Line

Returns a new Line that represents this line after transformation by the matrix

explicitClosestToPoint( point : Vector2 ) : ClosestToPointResult[]

Returns an object that gives information about the closest point (on a line segment) to the point argument

getSignedAreaFragment() : number

Returns the contribution to the signed area computed using Green's Theorem, with P=-y/2 and Q=x/2.

NOTE: This is this segment's contribution to the line integral (-y/2 dx + x/2 dy).

reparameterized( a : number, b : number ) : Line

Given the current curve parameterized by t, will return a curve parameterized by x where t = a * x + b

reversed() : Line

Returns a reversed copy of this segment (mapping the parametrization from [0,1] => [1,0]).

polarToCartesian( options : PiecewiseLinearOptions ) : Segment[]

Convert a line in the \((theta,r)\) plane of the form \((\theta_1,r_1)\) to \((\theta_2,r_2)\) and converts to the cartesian coordinate system

E.g. a polar line (0,1) to (2 Pi,1) would be mapped to a circle of radius 1

getArcLength() : number

Returns the arc length of the segment.

toPiecewiseLinearOrArcSegments() : Segment[]

We can handle this simply by returning ourselves.

serialize() : SerializedLine

Returns an object form that can be turned back into a segment with the corresponding deserialize method.

getOverlaps( segment : Segment, epsilon ) : Overlap[] | null

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param segment @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

getClosestPoints( point : Vector2 ) : ClosestToPointResult[]

Static Methods

deserialize( obj : SerializedLine ) : Line

Returns a Line from the serialized representation.

getOverlaps( line1 : Line, line2 : Line, epsilon ) : Overlap[]

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param line1 @param line2 @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

intersect( a : Line, b : Line ) : SegmentIntersection[]

Returns any (finite) intersection between the two line segments.

intersectOther( line : Line, other : Segment ) : SegmentIntersection[]

Returns any intersections between a line segment and another type of segment.

This should be more optimized than the general intersection routine of arbitrary segments.

Type PiecewiseLinearOptions

import type { PiecewiseLinearOptions } from 'scenerystack/kite';

Class Quadratic

Quadratic Bezier segment

Good reference: http://cagd.cs.byu.edu/~557/text/ch2.pdf

@author Jonathan Olson <jonathan.olson@colorado.edu>

import { Quadratic } from 'scenerystack/kite';

Constructor

new Quadratic( start : Vector2, control : Vector2, end : Vector2 )

Instance Methods

setStart( start : Vector2 ) : this

Sets the start point of the Quadratic.

getStart() : Vector2

Returns the start of this Quadratic.

setControl( control : Vector2 ) : this

Sets the control point of the Quadratic.

getControl() : Vector2

Returns the control point of this Quadratic.

setEnd( end : Vector2 ) : this

Sets the end point of the Quadratic.

getEnd() : Vector2

Returns the end of this Quadratic.

positionAt( t : number ) : Vector2

Returns the position parametrically, with 0 <= t <= 1.

NOTE: positionAt( 0 ) will return the start of the segment, and positionAt( 1 ) will return the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

tangentAt( t : number ) : Vector2

Returns the non-normalized tangent (dx/dt, dy/dt) of this segment at the parametric value of t, with 0 <= t <= 1.

NOTE: tangentAt( 0 ) will return the tangent at the start of the segment, and tangentAt( 1 ) will return the tangent at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

curvatureAt( t : number ) : number

Returns the signed curvature of the segment at the parametric value t, where 0 <= t <= 1.

The curvature will be positive for visual clockwise / mathematical counterclockwise curves, negative for opposite curvature, and 0 for no curvature.

NOTE: curvatureAt( 0 ) will return the curvature at the start of the segment, and curvatureAt( 1 ) will return the curvature at the end of the segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

subdivided( t : number ) : Quadratic[]

Returns an array with up to 2 sub-segments, split at the parametric t value. Together (in order) they should make up the same shape as the current segment.

This method is part of the Segment API. See Segment.js's constructor for more API documentation.

invalidate()

Clears cached information, should be called when any of the 'constructor arguments' are mutated.

getStartTangent() : Vector2

Returns the tangent vector (normalized) to the segment at the start, pointing in the direction of motion (from start to end)

getEndTangent() : Vector2

Returns the tangent vector (normalized) to the segment at the end, pointing in the direction of motion (from start to end)

getTCriticalX() : number

getTCriticalY() : number

getNondegenerateSegments() : Segment[]

Returns a list of non-degenerate segments that are equivalent to this segment. Generally gets rid (or simplifies) invalid or repeated segments.

getBounds() : Bounds2

Returns the bounds of this segment.

offsetTo( r : number, reverse : boolean ) : Quadratic[]

Returns an array of quadratic that are offset to this quadratic by a distance r

@param r - distance @param reverse

degreeElevated() : Cubic

Elevation of this quadratic Bezier curve to a cubic Bezier curve

approximateOffset( r : number ) : Quadratic

@param r - distance

getSVGPathFragment() : string

Returns a string containing the SVG path. assumes that the start point is already provided, so anything that calls this needs to put the M calls first

strokeLeft( lineWidth : number ) : Quadratic[]

Returns an array of lines that will draw an offset curve on the logical left side

strokeRight( lineWidth : number ) : Quadratic[]

Returns an array of lines that will draw an offset curve on the logical right side

getInteriorExtremaTs() : number[]

intersection( ray : Ray2 ) : RayIntersection[]

Hit-tests this segment with the ray. An array of all intersections of the ray with this segment will be returned. For details, see the documentation in Segment.js

windingIntersection( ray : Ray2 ) : number

Returns the winding number for intersection with a ray

writeToContext( context : CanvasRenderingContext2D )

Draws the segment to the 2D Canvas context, assuming the context's current location is already at the start point

transformed( matrix : Matrix3 ) : Quadratic

Returns a new quadratic that represents this quadratic after transformation by the matrix

getSignedAreaFragment() : number

Returns the contribution to the signed area computed using Green's Theorem, with P=-y/2 and Q=x/2.

NOTE: This is this segment's contribution to the line integral (-y/2 dx + x/2 dy).

reparameterized( a : number, b : number ) : Quadratic

Given the current curve parameterized by t, will return a curve parameterized by x where t = a * x + b

reversed() : Quadratic

Returns a reversed copy of this segment (mapping the parametrization from [0,1] => [1,0]).

serialize() : SerializedQuadratic

Returns an object form that can be turned back into a segment with the corresponding deserialize method.

getOverlaps( segment : Segment, epsilon ) : Overlap[] | null

Determine whether two lines overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

@param segment @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

Instance Properties

degree : number

Degree of the polynomial (quadratic)

Static Methods

deserialize( obj : SerializedQuadratic ) : Quadratic

Returns a Quadratic from the serialized representation.

extremaT( start : number, control : number, end : number ) : number

One-dimensional solution to extrema

getOverlaps( quadratic1 : Quadratic, quadratic2 : Quadratic, epsilon ) : Overlap[]

Determine whether two Quadratics overlap over a continuous section, and if so finds the a,b pair such that p( t ) === q( a * t + b ).

NOTE: for this particular function, we assume we're not degenerate. Things may work if we can be degree-reduced to a quadratic, but generally that shouldn't be done.

@param quadratic1 @param quadratic2 @param [epsilon] - Will return overlaps only if no two corresponding points differ by this amount or more in one component. @returns - The solution, if there is one (and only one)

Type SerializedArc

import type { SerializedArc } from 'scenerystack/kite';
  • type: "Arc"
  • centerX: number
  • centerY: number
  • radius: number
  • startAngle: number
  • endAngle: number
  • anticlockwise: boolean

Type SerializedCubic

import type { SerializedCubic } from 'scenerystack/kite';
  • type: "Cubic"
  • startX: number
  • startY: number
  • control1X: number
  • control1Y: number
  • control2X: number
  • control2Y: number
  • endX: number
  • endY: number

Type SerializedEllipticalArc

import type { SerializedEllipticalArc } from 'scenerystack/kite';
  • type: "EllipticalArc"
  • centerX: number
  • centerY: number
  • radiusX: number
  • radiusY: number
  • rotation: number
  • startAngle: number
  • endAngle: number
  • anticlockwise: boolean

Type SerializedLine

import type { SerializedLine } from 'scenerystack/kite';
  • type: "Line"
  • startX: number
  • startY: number
  • endX: number
  • endY: number

Type SerializedQuadratic

import type { SerializedQuadratic } from 'scenerystack/kite';
  • type: "Quadratic"
  • startX: number
  • startY: number
  • controlX: number
  • controlY: number
  • endX: number
  • endY: number

Type SerializedSegment

import type { SerializedSegment } from 'scenerystack/kite';

SerializedArc | SerializedCubic | SerializedEllipticalArc | SerializedLine | SerializedQuadratic

Source Code

See the source for Segment.ts in the kite repository.