// import b2 from './bezier2'; import b3 from './bezier3'; import extE2 from './extE2'; import gauss from './gauss'; import GeometricE2 from './GeometricE2'; import GeometricNumber from './GeometricNumber'; import GeometricOperators from './GeometricOperators'; import ImmutableMeasure from './ImmutableMeasure'; import lcoE2 from './lcoE2'; import mulE2 from './mulE2'; import notImplemented from '../i18n/notImplemented'; import notSupported from '../i18n/notSupported'; // import readOnly from '../i18n/readOnly'; import rcoE2 from './rcoE2'; import scpE2 from './scpE2'; import SpinorE2 from './SpinorE2'; // import stringFromCoordinates from './stringFromCoordinates'; // import TrigMethods from './TrigMethods'; import {Unit} from './Unit'; import VectorE2 from './VectorE2'; // // // // const COORD_SCALAR = 0 const COORD_X = 1 const COORD_Y = 2 // // // // const COORD_PSEUDO = 3 function add00(a00: number, a01: number, a10: number, a11: number, b00: number, b01: number, b10: number, b11: number): number { a00 = +a00; a01 = +a01; a10 = +a10; a11 = +a11; b00 = +b00; b01 = +b01; b10 = +b10; b11 = +b11; return +(a00 + b00); } function add01(a00: number, a01: number, a10: number, a11: number, b00: number, b01: number, b10: number, b11: number): number { a00 = +a00; a01 = +a01; a10 = +a10; a11 = +a11; b00 = +b00; b01 = +b01; b10 = +b10; b11 = +b11; return +(a01 + b01); } function add10(a00: number, a01: number, a10: number, a11: number, b00: number, b01: number, b10: number, b11: number): number { a00 = +a00; a01 = +a01; a10 = +a10; a11 = +a11; b00 = +b00; b01 = +b01; b10 = +b10; b11 = +b11; return +(a10 + b10); } function add11(a00: number, a01: number, a10: number, a11: number, b00: number, b01: number, b10: number, b11: number): number { a00 = +a00; a01 = +a01; a10 = +a10; a11 = +a11; b00 = +b00; b01 = +b01; b10 = +b10; b11 = +b11; return +(a11 + b11); } function subE2(a0: number, a1: number, a2: number, a3: number, b0: number, b1: number, b2: number, b3: number, index: number): number { a0 = +a0; a1 = +a1; a2 = +a2; a3 = +a3; b0 = +b0; b1 = +b1; b2 = +b2; b3 = +b3; index = index | 0; var x = 0.0; switch (~(~index)) { case 0: { x = +(a0 - b0); } break; case 1: { x = +(a1 - b1); } break; case 2: { x = +(a2 - b2); } break; case 3: { x = +(a3 - b3); } break; default: { throw new Error("index must be in the range [0..3]"); } } return +x; } /** *

* The G2 class represents a multivector for a 2-dimensional vector space with a Euclidean metric. *

*

* The G2 class is immutable, making it easy to reason about values. *

*

* The G2 class supports units of measures. *

*

* The immutable nature of the

G2

makes it less suitable for high performance graphics applications. *

*/ export class G2 implements ImmutableMeasure, GeometricE2, GeometricNumber, GeometricOperators, TrigMethods { /** * The coordinate values are stored in a number array. * This should be convenient and efficient for tensor calculations. * * @property _coords * @type number[] * @private */ private _coords: number[] = [0, 0, 0, 0] /** * @property uom * @type {Unit} */ public uom: Unit; /** * @property _zero * @type G2 * @static * @private */ private static _zero = new G2(0, 0, 0, 0) /** * @property zero * @type G2 * @static * @readOnly */ public static get zero() { return G2._zero } public static set zero(unused) { throw new Error(readOnly('zero').message) } /** * @property _one * @type G2 * @static * @private */ private static _one = new G2(1, 0, 0, 0) /** * @property one * @type G2 * @static * @readOnly */ public static get one() { return G2._one } public static set one(unused) { throw new Error(readOnly('one').message) } /** * @property _e2 * @type G2 * @static * @private */ private static _e1 = new G2(0, 1, 0, 0) /** * @property e1 * @type G2 * @static * @readOnly */ public static get e1() { return G2._e1 } public static set e1(unused) { throw new Error(readOnly('e1').message) } /** * @property _e2 * @type G2 * @static * @private */ private static _e2 = new G2(0, 0, 1, 0) /** * @property e2 * @type G2 * @static * @readOnly */ public static get e2() { return G2._e2 } public static set e2(unused) { throw new Error(readOnly('e2').message) } /** * @property _I * @type G2 * @static * @private */ private static _I = new G2(0, 0, 0, 1) /** * @property I * @type G2 * @static * @readOnly */ public static get I() { return G2._I } public static set I(unused) { throw new Error(readOnly('I').message) } public static kilogram = new G2(1, 0, 0, 0, Unit.KILOGRAM) public static meter = new G2(1, 0, 0, 0, Unit.METER) public static second = new G2(1, 0, 0, 0, Unit.SECOND) public static coulomb = new G2(1, 0, 0, 0, Unit.COULOMB) public static ampere = new G2(1, 0, 0, 0, Unit.AMPERE) public static kelvin = new G2(1, 0, 0, 0, Unit.KELVIN) public static mole = new G2(1, 0, 0, 0, Unit.MOLE) public static candela = new G2(1, 0, 0, 0, Unit.CANDELA) /** * @class G2 * @constructor * @param [α = 0] {number} The scalar part of the multivector. * @param [x = 0] {number} The vector component of the multivector in the x-direction. * @param [y = 0] {number} The vector component of the multivector in the y-direction. * @param [β = 0] {number} The pseudoscalar part of the multivector. * @param [uom] The optional unit of measure. */ constructor(α = 0, x = 0, y = 0, β = 0, uom?: Unit) { this._coords[COORD_SCALAR] = α this._coords[COORD_X] = x this._coords[COORD_Y] = y this._coords[COORD_PSEUDO] = β this.uom = uom if (this.uom && this.uom.multiplier !== 1) { const multiplier: number = this.uom.multiplier; this._coords[COORD_SCALAR] *= multiplier; this._coords[COORD_X] *= multiplier; this._coords[COORD_Y] *= multiplier; this._coords[COORD_PSEUDO] *= multiplier; this.uom = new Unit(1, uom.dimensions, uom.labels); } } /** * The scalar part of this multivector. */ get a(): number { return this._coords[COORD_SCALAR] } set a(unused) { throw new Error(readOnly('a').message) } /** * The coordinate corresponding to the e1 basis vector, without the unit of measure. * * @property x * @type number * @readOnly */ get x(): number { return this._coords[COORD_X] } set x(unused) { throw new Error(readOnly('x').message) } /** * The coordinate corresponding to the e2 basis vector, without the unit of measure. * * @property y * @type number * @readOnly */ get y(): number { return this._coords[COORD_Y] } set y(unused) { throw new Error(readOnly('y').message) } /** * The pseudoscalar part of this multivector. * @property beta * @type number * @readOnly */ get b(): number { return this._coords[COORD_PSEUDO] } set b(unused) { throw new Error(readOnly('b').message) } static fromCartesian(α: number, x: number, y: number, β: number, uom: Unit): G2 { return new G2(α, x, y, β, uom) } get coords(): number[] { return [this.a, this.x, this.y, this.b]; } coordinate(index: number): number { switch (index) { case 0: return this.a; case 1: return this.x; case 2: return this.y; case 3: return this.b; default: throw new Error("index must be in the range [0..3]"); } } // FIXME: This function forces the creation of temporary arrays. private static add(a: number[], b: number[]): number[] { const a00 = a[0]; const a01 = a[1]; const a10 = a[2]; const a11 = a[3]; const b00 = b[0]; const b01 = b[1]; const b10 = b[2]; const b11 = b[3]; const x00 = add00(a00, a01, a10, a11, b00, b01, b10, b11); const x01 = add01(a00, a01, a10, a11, b00, b01, b10, b11); const x10 = add10(a00, a01, a10, a11, b00, b01, b10, b11); const x11 = add11(a00, a01, a10, a11, b00, b01, b10, b11); return [x00, x01, x10, x11]; } /** * @method add * @param rhs {G2} * @return {G2} * @chainable */ add(rhs: G2): G2 { var xs = G2.add(this.coords, rhs.coords); return new G2(xs[0], xs[1], xs[2], xs[3], Unit.compatible(this.uom, rhs.uom)); } /** * Computes this + Iβ */ addPseudo(β: Unit): G2 { return new G2(this.a, this.x, this.y, this.b + β.multiplier, Unit.compatible(this.uom, β)) } /** * Computes this + α */ addScalar(α: Unit): G2 { return new G2(this.a + α.multiplier, this.x, this.y, this.b, Unit.compatible(this.uom, α)) } __add__(other: any): G2 { if (other instanceof G2) { return this.add(other); } else if (typeof other === 'number') { return this.add(new G2(other, 0, 0, 0, undefined)); } } __radd__(other: any): G2 { if (other instanceof G2) { return (other).add(this); } else if (typeof other === 'number') { return new G2(other, 0, 0, 0, undefined).add(this); } } adj(): G2 { throw new Error(notImplemented('adj').message) } /** * @returns grade(log(this), 2) */ angle(): G2 { return this.log().grade(2); } /** * Computes the Clifford conjugate of this multivector. * The grade multiplier is -1x(x+1)/2 */ conj(): G2 { throw new Error(notImplemented('conj').message) } /** * @param t * @param controlBegin * @param controlEnd * @param endPoint */ cubicBezier(t: number, controlBegin: GeometricE2, controlEnd: GeometricE2, endPoint: GeometricE2) { const α = b3(t, this.a, controlBegin.a, controlEnd.a, endPoint.a) const x = b3(t, this.x, controlBegin.x, controlEnd.x, endPoint.x) const y = b3(t, this.y, controlBegin.y, controlEnd.y, endPoint.y) const β = b3(t, this.b, controlBegin.b, controlEnd.b, endPoint.b) return new G2(α, x, y, β, this.uom); } /** * @method direction * @return {G2} * @chainable */ public direction(): G2 { const m: number = this.magnitudeSansUnits() if (m !== 1) { return new G2(this.a / m, this.x / m, this.y / m, this.b / m) } else { if (this.uom) { return new G2(this.a, this.x, this.y, this.b) } else { return this } } } /** * @param point */ distanceTo(point: GeometricE2): number { throw new Error(notImplemented('distanceTo').message) } /** * @method equals * @param other {any} * @return {boolean} */ equals(point: GeometricE2): boolean { throw new Error(notImplemented('equals').message) } private static sub(a: number[], b: number[]): number[] { var a0 = a[0]; var a1 = a[1]; var a2 = a[2]; var a3 = a[3]; var b0 = b[0]; var b1 = b[1]; var b2 = b[2]; var b3 = b[3]; var x0 = subE2(a0, a1, a2, a3, b0, b1, b2, b3, 0); var x1 = subE2(a0, a1, a2, a3, b0, b1, b2, b3, 1); var x2 = subE2(a0, a1, a2, a3, b0, b1, b2, b3, 2); var x3 = subE2(a0, a1, a2, a3, b0, b1, b2, b3, 3); return [x0, x1, x2, x3]; } /** * */ sub(rhs: G2): G2 { var xs = G2.sub(this.coords, rhs.coords); return new G2(xs[0], xs[1], xs[2], xs[3], Unit.compatible(this.uom, rhs.uom)); } __sub__(rhs: Unit | G2 | number): G2 { if (rhs instanceof G2) { return this.sub(rhs); } else if (rhs instanceof Unit) { return this.addScalar(rhs.neg()); } else if (typeof rhs === 'number') { return this.sub(new G2(rhs, 0, 0, 0, undefined)); } } __rsub__(lhs: Unit | G2 | number): G2 { if (lhs instanceof G2) { return lhs.sub(this); } else if (lhs instanceof Unit) { return this.neg().addScalar(lhs) } else if (typeof lhs === 'number') { return new G2(lhs, 0, 0, 0, undefined).sub(this); } } mul(rhs: G2): G2 { const a0 = this.a const a1 = this.x const a2 = this.y const a3 = this.b const b0 = rhs.a const b1 = rhs.x const b2 = rhs.y const b3 = rhs.b // TODO: Split into four functions to avoid conditionals or inline. const c0 = mulE2(a0, a1, a2, a3, b0, b1, b2, b3, 0) const c1 = mulE2(a0, a1, a2, a3, b0, b1, b2, b3, 1) const c2 = mulE2(a0, a1, a2, a3, b0, b1, b2, b3, 2) const c3 = mulE2(a0, a1, a2, a3, b0, b1, b2, b3, 3) return new G2(c0, c1, c2, c3, Unit.mul(this.uom, rhs.uom)) } __mul__(other: any): G2 { if (other instanceof G2) { return this.mul(other); } else if (typeof other === 'number') { return this.mul(new G2(other, 0, 0, 0, undefined)); } } __rmul__(other: any): G2 { if (other instanceof G2) { var lhs: G2 = other; return lhs.mul(this); } else if (typeof other === 'number') { var w: number = other; return new G2(w, 0, 0, 0, undefined).mul(this); } } scale(α: number): G2 { return new G2(this.a * α, this.x * α, this.y * α, this.b * α, this.uom); } div(rhs: G2): G2 { return this.mul(rhs.inv()) } divByScalar(α: number): G2 { return new G2(this.a / α, this.x / α, this.y / α, this.b / α, this.uom); } __div__(other: any): G2 { if (other instanceof G2) { return this.div(other); } else if (typeof other === 'number') { var w: number = other; return this.div(new G2(w, 0, 0, 0, undefined)); } } __rdiv__(other: number | G2): G2 { if (other instanceof G2) { return other.div(this); } else if (typeof other === 'number') { return new G2(other, 0, 0, 0, undefined).div(this); } } /** * @method scp * @param rhs {G2} * @return {G2} * @chainable */ scp(rhs: G2): G2 { const a0 = this.a const a1 = this.x const a2 = this.y const a3 = this.b const b0 = rhs.a const b1 = rhs.x const b2 = rhs.y const b3 = rhs.b const c0 = scpE2(a0, a1, a2, a3, b0, b1, b2, b3, 0) return new G2(c0, 0, 0, 0, Unit.mul(this.uom, rhs.uom)) } private static ext(a: number[], b: number[]): number[] { const a0: number = a[0]; const a1: number = a[1]; const a2: number = a[2]; const a3: number = a[3]; const b0: number = b[0]; const b1: number = b[1]; const b2: number = b[2]; const b3: number = b[3]; const x0: number = extE2(a0, a1, a2, a3, b0, b1, b2, b3, 0); const x1: number = extE2(a0, a1, a2, a3, b0, b1, b2, b3, 1); const x2: number = extE2(a0, a1, a2, a3, b0, b1, b2, b3, 2); const x3: number = extE2(a0, a1, a2, a3, b0, b1, b2, b3, 3); return [x0, x1, x2, x3]; } /** * @method ext * @param rhs {G2} * @return {G2} * @chainable */ ext(rhs: G2): G2 { var xs = G2.ext(this.coords, rhs.coords); return new G2(xs[0], xs[1], xs[2], xs[3], Unit.mul(this.uom, rhs.uom)); } __wedge__(other: any): G2 { if (other instanceof G2) { var rhs: G2 = other; return this.ext(rhs); } else if (typeof other === 'number') { var w: number = other; return this.ext(new G2(w, 0, 0, 0, undefined)); } } __rwedge__(other: any): G2 { if (other instanceof G2) { var lhs: G2 = other; return lhs.ext(this); } else if (typeof other === 'number') { var w: number = other; return new G2(w, 0, 0, 0, undefined).ext(this); } } private static lshift(a: number[], b: number[]): number[] { var a0 = a[0]; var a1 = a[1]; var a2 = a[2]; var a3 = a[3]; var b0 = b[0]; var b1 = b[1]; var b2 = b[2]; var b3 = b[3]; var x0 = lcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 0); var x1 = lcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 1); var x2 = lcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 2); var x3 = lcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 3); return [x0, x1, x2, x3]; } /** * @method lerp * @param target {G2} * @param α {number} * @return {G2} * @chainable */ lerp(target: G2, α: number): G2 { throw new Error(notImplemented('lerp').message) } /** * @method lco * @param lhs {G2} * @return {G2} * @chainable */ lco(rhs: G2): G2 { var xs = G2.lshift(this.coords, rhs.coords); return new G2(xs[0], xs[1], xs[2], xs[3], Unit.mul(this.uom, rhs.uom)); } __lshift__(other: any): G2 { if (other instanceof G2) { var rhs: G2 = other; return this.lco(rhs); } else if (typeof other === 'number') { var w: number = other; return this.lco(new G2(w, 0, 0, 0, undefined)); } } __rlshift__(other: any): G2 { if (other instanceof G2) { var lhs: G2 = other; return lhs.lco(this); } else if (typeof other === 'number') { var w: number = other; return new G2(w, 0, 0, 0, undefined).lco(this); } } private static rshift(a: number[], b: number[]): number[] { var a0 = a[0]; var a1 = a[1]; var a2 = a[2]; var a3 = a[3]; var b0 = b[0]; var b1 = b[1]; var b2 = b[2]; var b3 = b[3]; var x0 = rcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 0); var x1 = rcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 1); var x2 = rcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 2); var x3 = rcoE2(a0, a1, a2, a3, b0, b1, b2, b3, 3); return [x0, x1, x2, x3]; } /** * @method rco * @param rhs {G2} * @return {G2} * @chainable */ rco(rhs: G2): G2 { var xs = G2.rshift(this.coords, rhs.coords); return new G2(xs[0], xs[1], xs[2], xs[3], Unit.mul(this.uom, rhs.uom)); } __rshift__(other: any): G2 { if (other instanceof G2) { return this.rco(other); } else if (typeof other === 'number') { return this.rco(new G2(other, 0, 0, 0, undefined)); } } __rrshift__(other: any): G2 { if (other instanceof G2) { return (other).rco(this); } else if (typeof other === 'number') { return new G2(other, 0, 0, 0, undefined).rco(this); } } __vbar__(other: any): G2 { if (other instanceof G2) { return this.scp(other); } else if (typeof other === 'number') { return this.scp(new G2(other, 0, 0, 0, undefined)); } } __rvbar__(other: any): G2 { if (other instanceof G2) { return (other).scp(this); } else if (typeof other === 'number') { return new G2(other, 0, 0, 0, undefined).scp(this); } } /** * @method pow * @param exponent {G2} * @return {G2} * @chainable */ pow(exponent: G2): G2 { throw new Error(notImplemented('pow').message) } __bang__(): G2 { return this.inv() } __pos__(): G2 { return this } /** * @method neg * @return {G2} * @chainable */ neg(): G2 { return new G2(-this.a, -this.x, -this.y, -this.b, this.uom) } __neg__(): G2 { return this.neg() } /** * ~ (tilde) produces reversion. */ __tilde__(): G2 { return this.rev() } /** * @method grade * @param grade {number} * @return {G2} * @chainable */ grade(grade: number): G2 { switch (grade) { case 0: return new G2(this.a, 0, 0, 0, this.uom); case 1: return new G2(0, this.x, this.y, 0, this.uom); case 2: return new G2(0, 0, 0, this.b, this.uom); default: return new G2(0, 0, 0, 0, this.uom); } } /** * @method cos * @return {G2} * @chainable */ cos(): G2 { throw new Error(notImplemented('cos').message) } /** * @method cosh * @return {G2} * @chainable */ cosh(): G2 { throw new Error(notImplemented('cosh').message) } /** * @method exp * @return {G2} * @chainable */ exp(): G2 { Unit.assertDimensionless(this.uom) if (this.isSpinor()) { const expα = Math.exp(this.a) const cosβ = Math.cos(this.b) const sinβ = Math.sin(this.b) return new G2(expα * cosβ, 0, 0, expα * sinβ) } else { throw new Error(notImplemented(`exp(${this.toString()})`).message) } } /** * Computes the inverse of this multivector, if it exists. * * @method inv * @return {G2} * @chainable */ inv(): G2 { const α = this.a const x = this.x const y = this.y const β = this.b const A = [ [α, x, y, -β], [x, α, β, -y], [y, -β, α, x], [β, -y, x, α] ] const b = [1, 0, 0, 0] const X = gauss(A, b) const uom = this.uom ? this.uom.inv() : void 0 return new G2(X[0], X[1], X[2], X[3], uom); } /** * Determines whether this multivector has only grade 0 and grade 2 components. */ isSpinor(): boolean { return this.x === 0 && this.y === 0 } /** * */ log(): G2 { Unit.assertDimensionless(this.uom); if (this.isSpinor()) { const α = this.a; const β = this.b; const a = Math.log(Math.sqrt(α * α + β * β)); const b = Math.atan2(β, α); return new G2(a, 0, 0, b, void 0); } else { throw new Error(notImplemented(`log(${this.toString()})`).message); } } /** * Computes the square root of the squared norm. */ magnitude(): G2 { return this.norm() } /** * Intentionally undocumented. */ magnitudeSansUnits(): number { return Math.sqrt(this.squaredNormSansUnits()) } /** * @method norm * @return {G2} * @chainable */ norm(): G2 { return new G2(this.magnitudeSansUnits(), 0, 0, 0, this.uom); } /** * @method quad * @return {G2} * @chainable */ quad(): G2 { return new G2(this.squaredNormSansUnits(), 0, 0, 0, Unit.mul(this.uom, this.uom)); } /** * @method quadraticBezier * @param t {number} * @param controlPoint {GeometricE2} * @param endPoint {GeometricE2} * @return {G2} * @chainable */ quadraticBezier(t: number, controlPoint: GeometricE2, endPoint: GeometricE2): G2 { const α = b2(t, this.a, controlPoint.a, endPoint.a) const x = b2(t, this.x, controlPoint.x, endPoint.x) const y = b2(t, this.y, controlPoint.y, endPoint.y) const β = b2(t, this.b, controlPoint.b, endPoint.b) return new G2(α, x, y, β, this.uom); } /** * @method squaredNorm * @return {G2} * @chainable */ public squaredNorm(): G2 { return this.quad() } /** * Intentionally undocumented. */ public squaredNormSansUnits(): number { const α = this.a const x = this.x const y = this.y const β = this.b return α * α + x * x + y * y + β * β } /** * @method stress * @param σ {VectorE2} * @return {G2} * @chainable */ stress(σ: VectorE2): G2 { throw new Error(notSupported('stress').message) } /** * Computes the reflection of this multivector in the plane with normal n. * * * @method reflect * @param n {VectorE2} * @return {G2} * @chainable */ reflect(n: VectorE2): G2 { // TODO: Optimize to minimize object creation and increase performance. const m = G2.fromVectorE2(n) return m.mul(this).mul(m).scale(-1) } /** * @method rev * @return {G2} * @chainable */ rev(): G2 { return new G2(this.a, this.x, this.y, -this.b, this.uom) } /** * @method rotate * @param spinor {SpinorE2} * @return {G2} * @chainable */ rotate(spinor: SpinorE2): G2 { const x = this.x const y = this.y const α = spinor.a const β = spinor.b const α2 = α * α const β2 = β * β const p = α2 - β2 const q = 2 * α * β const s = α2 + β2 return new G2(s * this.a, p * x + q * y, p * y - q * x, s * this.b, this.uom) } /** * @method sin * @return {G2} * @chainable */ sin(): G2 { throw new Error(notImplemented('sin').message) } /** * @method sinh * @return {G2} * @chainable */ sinh(): G2 { throw new Error(notImplemented('sinh').message) } /** * @method slerp * @param target {G2} * @param α {number} * @return {G2} * @chainable */ slerp(target: G2, α: number): G2 { throw new Error(notImplemented('slerp').message) } /** * @method tan * @return {G2} * @chainable */ tan(): G2 { return this.sin().div(this.cos()) } /** * @method isOne * @return {boolean} */ isOne(): boolean { return this.a === 1 && this.x === 0 && this.y === 0 && this.b === 0 } isNaN(): boolean { return isNaN(this.a) || isNaN(this.x) || isNaN(this.y) || isNaN(this.b) } isScalar(): boolean { return this.x === 0 && this.y === 0 && this.b === 0 } /** * @method isZero * @return {boolean} */ isZero(): boolean { return this.a === 0 && this.x === 0 && this.y === 0 && this.b === 0 } private toStringCustom( coordToString: (x: number) => string, labels: string[]): string { const quantityString: string = stringFromCoordinates(this.coords, coordToString, labels); if (this.uom) { // Use the compact representation of the Unit because the units follow the multivector // quantity and we want to suppress the multiplier which is always 1. const unitString = this.uom.toString(10, true).trim(); if (unitString) { return quantityString + ' ' + unitString; } else { return quantityString; } } else { return quantityString; } } /** * @method toExponential * @param [fractionDigits] {number} * @return {string} */ public toExponential(fractionDigits?: number): string { const coordToString = function (coord: number): string { return coord.toExponential(fractionDigits) }; return this.toStringCustom(coordToString, ["1", "e1", "e2", "e12"]); } /** * @method toFixed * @param [fractionDigits] {number} * @return {string} */ public toFixed(fractionDigits?: number): string { const coordToString = function (coord: number): string { return coord.toFixed(fractionDigits) }; return this.toStringCustom(coordToString, ["1", "e1", "e2", "e12"]); } /** * @method toPrecision * @param [precision] {number} * @return {string} */ public toPrecision(precision?: number): string { const coordToString = function (coord: number): string { return coord.toPrecision(precision) }; return this.toStringCustom(coordToString, ["1", "e1", "e2", "e12"]); } /** * @method toString * @param [radix] {number} * @return {string} */ public toString(radix?: number): string { const coordToString = function (coord: number): string { return coord.toString(radix) }; return this.toStringCustom(coordToString, ["1", "e1", "e2", "e12"]); } toStringIJK(): string { var coordToString = function (coord: number): string { return coord.toString() }; return this.toStringCustom(coordToString, ["1", "i", "j", "I"]); } __eq__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in equality expression: ${this.uom.dimensions} === ${rhs.uom.dimensions}`); } return this.a === rhs.a && this.x === rhs.x && this.y === rhs.y && this.b === rhs.b; } else { return void 0; } } __ne__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in inequality expression: ${this.uom.dimensions} !== ${rhs.uom.dimensions}`); } return this.a !== rhs.a || this.x !== rhs.x || this.y !== rhs.y || this.b !== this.b; } else { return void 0; } } __ge__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in comparison expression: ${this.uom.dimensions} >= ${rhs.uom.dimensions}`); } if (!this.isScalar()) { throw new Error(`left operand (${this}) in comparison expression must be a scalar.`); } if (!rhs.isScalar()) { throw new Error(`right operand (${rhs}) in comparison expression must be a scalar.`); } return this.a >= rhs.a; } else { return void 0; } } __gt__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in comparison expression: ${this.uom.dimensions} > ${rhs.uom.dimensions}`); } if (!this.isScalar()) { throw new Error(`left operand (${this}) in comparison expression must be a scalar.`); } if (!rhs.isScalar()) { throw new Error(`right operand (${rhs}) in comparison expression must be a scalar.`); } return this.a > rhs.a; } else { return void 0; } } __le__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in comparison expression: ${this.uom.dimensions} <= ${rhs.uom.dimensions}`); } if (!this.isScalar()) { throw new Error(`left operand (${this}) in comparison expression must be a scalar.`); } if (!rhs.isScalar()) { throw new Error(`right operand (${rhs}) in comparison expression must be a scalar.`); } return this.a <= rhs.a; } else { return void 0; } } __lt__(rhs: G2): boolean { if (rhs instanceof G2) { try { Unit.compatible(this.uom, rhs.uom); } catch (e) { throw new Error(`Dimensions mismatch in comparison expression: ${this.uom.dimensions} < ${rhs.uom.dimensions}`); } if (!this.isScalar()) { throw new Error(`left operand (${this}) in comparison expression must be a scalar.`); } if (!rhs.isScalar()) { throw new Error(`right operand (${rhs}) in comparison expression must be a scalar.`); } return this.a < rhs.a; } else { return void 0; } } /* private toStringLATEX(): string { var coordToString = function(coord: number): string { return coord.toString() }; return this.toStringCustom(coordToString, ["1", "e_{1}", "e_{2}", "e_{12}"]); } */ /** * @method copy * @param M {GeometricE2} * @return {G2} * @chainable * @static */ static copy(m: GeometricE2): G2 { if (m instanceof G2) { return m } else { return new G2(m.a, m.x, m.y, m.b, void 0) } } /** * @method fromVectorE2 * @param vector {VectorE2} * @return {G2} * @chainable * @static */ static fromVectorE2(vector: VectorE2): G2 { if (vector) { if (vector instanceof G2) { return new G2(0, vector.x, vector.y, 0, vector.uom) } else { return new G2(0, vector.x, vector.y, 0, void 0) } } else { return void 0 } } /** * @method vector * @param x {number} * @param y {number} * @param [uom] {Unit} * @return {G2} * @chainable * @static */ static vector(x: number, y: number, uom?: Unit): G2 { return new G2(0, x, y, 0, uom) } }