Skip to content

Instantly share code, notes, and snippets.

@ksassnowski
Created February 14, 2023 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksassnowski/be32d5c84a40f968b6ba7992070bbc08 to your computer and use it in GitHub Desktop.
Save ksassnowski/be32d5c84a40f968b6ba7992070bbc08 to your computer and use it in GitHub Desktop.
Typescript Polynomial implementation based on Freya Holmér's "Mathfs" package for Unity
export type Derivative = 0 | 1 | 2 | 3;
/**
* A polynomial in the form ax^3+bx^2+cx+d up to a cubic.
*/
export class Polynomial {
public readonly c1: number;
public readonly c2: number;
public readonly c3: number;
/**
* Constructs a constant polynomial
*
* @param c0 The constant coefficient
*/
public static constant(constant: number): Polynomial {
return new Polynomial(constant);
}
/**
* Constructs a linear polynomial
*
* @param c0 The constant coefficient
* @param c1 The linear coefficient
*/
public static linear(c0: number, c1: number): Polynomial {
return new Polynomial(c0, c1);
}
/**
* Constructs a quadratic polynomial
*
* @param c0 The constant coefficient
* @param c1 The linear coefficient
* @param c2 The quadratic coefficient
*/
public static quadratic(c0: number, c1: number, c2: number): Polynomial {
return new Polynomial(c0, c1, c2);
}
/**
* Constructs a cubic polynomial
*
* @param c0 The constant coefficient
* @param c1 The linear coefficient
* @param c2 The quadratic coefficient
* @param c3 The cubic coefficient
*/
public static cubic(
c0: number,
c1: number,
c2: number,
c3: number,
): Polynomial {
return new Polynomial(c0, c1, c2, c3);
}
/**
* @param c0 The constant coefficient
*/
public constructor(c0: number);
/**
* @param c0 The constant coefficient
* @param c1 The linear coefficient
*/
public constructor(c0: number, c1: number);
/**
* @param c0 The constant coefficient
* @param c1 The linear coefficient
* @param c2 The quadratic coefficient
*/
public constructor(c0: number, c1: number, c2: number);
/**
* @param c0 The constant coefficient
* @param c1 The linear coefficient
* @param c2 The quadratic coefficient
* @param c3 The cubic coefficient
*/
public constructor(c0: number, c1: number, c2: number, c3: number);
public constructor(
public readonly c0: number,
c1?: number,
c2?: number,
c3?: number,
) {
this.c1 = c1 ?? 0;
this.c2 = c2 ?? 0;
this.c3 = c3 ?? 0;
}
/**
* Return the nths deriviative of the polynomial.
*
* @param n The number of times to differentiate the polynomial.
*/
public differentiate(n: Derivative = 1): Polynomial {
switch (n) {
case 0:
return this;
case 1:
return new Polynomial(this.c1, 2 * this.c2, 3 * this.c3, 0);
case 2:
return new Polynomial(2 * this.c2, 6 * this.c3, 0, 0);
case 3:
return new Polynomial(6 * this.c3, 0, 0, 0);
}
}
/**
* Evaluate the polynomial at the given value t.
*
* @param t The value to sample at
*/
public eval(t: number): number;
/**
* Evaluate the nth derivative of the polynomial at the given value t.
*
* @param t The value to sample at
* @param derivative The deriviate of the polynomial to sample from
*/
public eval(t: number, derivative: number): number;
public eval(t: number, derivative: Derivative = 0): number {
if (derivative !== 0) {
return this.differentiate(derivative).eval(t);
}
return this.c3 * (t * t * t) + this.c2 * (t * t) + this.c1 * t + this.c0;
}
public split(u: number): [Polynomial, Polynomial] {
const d = 1 - u;
const pre = new Polynomial(
this.c0,
this.c1 * u,
this.c2 * u * u,
this.c3 * u * u * u,
);
const post = new Polynomial(
this.eval(0),
d * this.differentiate(1).eval(u),
((d * d) / 2) * this.differentiate(2).eval(u),
((d * d * d) / 6) * this.differentiate(3).eval(u),
);
return [pre, post];
}
}
@ksassnowski
Copy link
Author

ksassnowski commented Feb 14, 2023

And here's the Polynomial2D implementation to create a polynomial based off of two vectors:

import { Derivative, Polynomial } from "./Polynomial";
import { Vector2 } from "Vector2";

export class Polynomial2D {
  public readonly x: Polynomial;
  public readonly y: Polynomial;

  public constructor(c0: Vector2, c1: Vector2, c2: Vector2, c3: Vector2);
  public constructor(c0: Vector2, c1: Vector2, c2: Vector2);
  public constructor(x: Polynomial, y: Polynomial);
  public constructor(
    public readonly c0: Vector2 | Polynomial,
    public readonly c1: Vector2 | Polynomial,
    public readonly c2?: Vector2,
    public readonly c3?: Vector2,
  ) {
    if (c0 instanceof Polynomial) {
      this.x = c0;
      this.y = c1 as Polynomial;
    } else if (c3 !== undefined) {
      this.x = new Polynomial(c0.x, (c1 as Vector2).x, c2.x, c3.x);
      this.y = new Polynomial(c0.y, (c1 as Vector2).y, c2.y, c3.y);
    } else {
      this.x = new Polynomial(c0.x, (c1 as Vector2).x, c2.x);
      this.y = new Polynomial(c0.y, (c1 as Vector2).y, c2.y);
    }
  }

  public eval(t: number, derivative: Derivative = 0): Vector2 {
    return new Vector2(
      this.x.differentiate(derivative).eval(t),
      this.y.differentiate(derivative).eval(t),
    );
  }

  public split(u: number): [Polynomial2D, Polynomial2D] {
    const [xPre, xPost] = this.x.split(u);
    const [yPre, yPost] = this.y.split(u);
    return [new Polynomial2D(xPre, yPre), new Polynomial2D(xPost, yPost)];
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment