UNPKG

@g20/core

Version:

Geometric Algebra 2D Graphics Library

1,162 lines (1,129 loc) 326 kB
/** * @g20/core 1.0.0-alpha.46 * (c) David Geo Holmes david.geo.holmes@gmail.com * Released under the MIT License. */ System.register(['@g20/reactive'], (function (exports) { 'use strict'; var signal, effect, computed; return { setters: [function (module) { signal = module.signal; effect = module.effect; computed = module.computed; }], execute: (function () { exports({ dispose: dispose, is_color: is_color, is_color_provider: is_color_provider, spinor_from_like: spinor_from_like, variable: variable, vector_from_like: vector_from_like }); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; function isFunction(value) { return typeof value === 'function'; } function createErrorClass(createImpl) { var _super = function (instance) { Error.call(instance); instance.stack = new Error().stack; }; var ctorFunc = createImpl(_super); ctorFunc.prototype = Object.create(Error.prototype); ctorFunc.prototype.constructor = ctorFunc; return ctorFunc; } var UnsubscriptionError = createErrorClass(function (_super) { return function UnsubscriptionErrorImpl(errors) { _super(this); this.message = errors ? errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n ') : ''; this.name = 'UnsubscriptionError'; this.errors = errors; }; }); function arrRemove(arr, item) { if (arr) { var index = arr.indexOf(item); 0 <= index && arr.splice(index, 1); } } var Subscription = (function () { function Subscription(initialTeardown) { this.initialTeardown = initialTeardown; this.closed = false; this._parentage = null; this._finalizers = null; } Subscription.prototype.unsubscribe = function () { var e_1, _a, e_2, _b; var errors; if (!this.closed) { this.closed = true; var _parentage = this._parentage; if (_parentage) { this._parentage = null; if (Array.isArray(_parentage)) { try { for (var _parentage_1 = __values(_parentage), _parentage_1_1 = _parentage_1.next(); !_parentage_1_1.done; _parentage_1_1 = _parentage_1.next()) { var parent_1 = _parentage_1_1.value; parent_1.remove(this); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_parentage_1_1 && !_parentage_1_1.done && (_a = _parentage_1.return)) _a.call(_parentage_1); } finally { if (e_1) throw e_1.error; } } } else { _parentage.remove(this); } } var initialFinalizer = this.initialTeardown; if (isFunction(initialFinalizer)) { try { initialFinalizer(); } catch (e) { errors = e instanceof UnsubscriptionError ? e.errors : [e]; } } var _finalizers = this._finalizers; if (_finalizers) { this._finalizers = null; try { for (var _finalizers_1 = __values(_finalizers), _finalizers_1_1 = _finalizers_1.next(); !_finalizers_1_1.done; _finalizers_1_1 = _finalizers_1.next()) { var finalizer = _finalizers_1_1.value; try { execFinalizer(finalizer); } catch (err) { errors = errors !== null && errors !== void 0 ? errors : []; if (err instanceof UnsubscriptionError) { errors = __spreadArray(__spreadArray([], __read(errors)), __read(err.errors)); } else { errors.push(err); } } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_finalizers_1_1 && !_finalizers_1_1.done && (_b = _finalizers_1.return)) _b.call(_finalizers_1); } finally { if (e_2) throw e_2.error; } } } if (errors) { throw new UnsubscriptionError(errors); } } }; Subscription.prototype.add = function (teardown) { var _a; if (teardown && teardown !== this) { if (this.closed) { execFinalizer(teardown); } else { if (teardown instanceof Subscription) { if (teardown.closed || teardown._hasParent(this)) { return; } teardown._addParent(this); } (this._finalizers = (_a = this._finalizers) !== null && _a !== void 0 ? _a : []).push(teardown); } } }; Subscription.prototype._hasParent = function (parent) { var _parentage = this._parentage; return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent)); }; Subscription.prototype._addParent = function (parent) { var _parentage = this._parentage; this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent; }; Subscription.prototype._removeParent = function (parent) { var _parentage = this._parentage; if (_parentage === parent) { this._parentage = null; } else if (Array.isArray(_parentage)) { arrRemove(_parentage, parent); } }; Subscription.prototype.remove = function (teardown) { var _finalizers = this._finalizers; _finalizers && arrRemove(_finalizers, teardown); if (teardown instanceof Subscription) { teardown._removeParent(this); } }; Subscription.EMPTY = (function () { var empty = new Subscription(); empty.closed = true; return empty; })(); return Subscription; }()); var EMPTY_SUBSCRIPTION = Subscription.EMPTY; function isSubscription(value) { return (value instanceof Subscription || (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))); } function execFinalizer(finalizer) { if (isFunction(finalizer)) { finalizer(); } else { finalizer.unsubscribe(); } } var config = { onUnhandledError: null, onStoppedNotification: null, Promise: undefined, useDeprecatedSynchronousErrorHandling: false, useDeprecatedNextContext: false, }; var timeoutProvider = { setTimeout: function (handler, timeout) { var args = []; for (var _i = 2; _i < arguments.length; _i++) { args[_i - 2] = arguments[_i]; } return setTimeout.apply(void 0, __spreadArray([handler, timeout], __read(args))); }, clearTimeout: function (handle) { return (clearTimeout)(handle); }, delegate: undefined, }; function reportUnhandledError(err) { timeoutProvider.setTimeout(function () { { throw err; } }); } function noop() { } function errorContext(cb) { { cb(); } } var Subscriber = (function (_super) { __extends(Subscriber, _super); function Subscriber(destination) { var _this = _super.call(this) || this; _this.isStopped = false; if (destination) { _this.destination = destination; if (isSubscription(destination)) { destination.add(_this); } } else { _this.destination = EMPTY_OBSERVER; } return _this; } Subscriber.create = function (next, error, complete) { return new SafeSubscriber(next, error, complete); }; Subscriber.prototype.next = function (value) { if (this.isStopped) ; else { this._next(value); } }; Subscriber.prototype.error = function (err) { if (this.isStopped) ; else { this.isStopped = true; this._error(err); } }; Subscriber.prototype.complete = function () { if (this.isStopped) ; else { this.isStopped = true; this._complete(); } }; Subscriber.prototype.unsubscribe = function () { if (!this.closed) { this.isStopped = true; _super.prototype.unsubscribe.call(this); this.destination = null; } }; Subscriber.prototype._next = function (value) { this.destination.next(value); }; Subscriber.prototype._error = function (err) { try { this.destination.error(err); } finally { this.unsubscribe(); } }; Subscriber.prototype._complete = function () { try { this.destination.complete(); } finally { this.unsubscribe(); } }; return Subscriber; }(Subscription)); var _bind = Function.prototype.bind; function bind(fn, thisArg) { return _bind.call(fn, thisArg); } var ConsumerObserver = (function () { function ConsumerObserver(partialObserver) { this.partialObserver = partialObserver; } ConsumerObserver.prototype.next = function (value) { var partialObserver = this.partialObserver; if (partialObserver.next) { try { partialObserver.next(value); } catch (error) { handleUnhandledError(error); } } }; ConsumerObserver.prototype.error = function (err) { var partialObserver = this.partialObserver; if (partialObserver.error) { try { partialObserver.error(err); } catch (error) { handleUnhandledError(error); } } else { handleUnhandledError(err); } }; ConsumerObserver.prototype.complete = function () { var partialObserver = this.partialObserver; if (partialObserver.complete) { try { partialObserver.complete(); } catch (error) { handleUnhandledError(error); } } }; return ConsumerObserver; }()); var SafeSubscriber = (function (_super) { __extends(SafeSubscriber, _super); function SafeSubscriber(observerOrNext, error, complete) { var _this = _super.call(this) || this; var partialObserver; if (isFunction(observerOrNext) || !observerOrNext) { partialObserver = { next: (observerOrNext !== null && observerOrNext !== void 0 ? observerOrNext : undefined), error: error !== null && error !== void 0 ? error : undefined, complete: complete !== null && complete !== void 0 ? complete : undefined, }; } else { var context_1; if (_this && config.useDeprecatedNextContext) { context_1 = Object.create(observerOrNext); context_1.unsubscribe = function () { return _this.unsubscribe(); }; partialObserver = { next: observerOrNext.next && bind(observerOrNext.next, context_1), error: observerOrNext.error && bind(observerOrNext.error, context_1), complete: observerOrNext.complete && bind(observerOrNext.complete, context_1), }; } else { partialObserver = observerOrNext; } } _this.destination = new ConsumerObserver(partialObserver); return _this; } return SafeSubscriber; }(Subscriber)); function handleUnhandledError(error) { { reportUnhandledError(error); } } function defaultErrorHandler(err) { throw err; } var EMPTY_OBSERVER = { closed: true, next: noop, error: defaultErrorHandler, complete: noop, }; var observable = (function () { return (typeof Symbol === 'function' && Symbol.observable) || '@@observable'; })(); function identity(x) { return x; } function pipeFromArray(fns) { if (fns.length === 0) { return identity; } if (fns.length === 1) { return fns[0]; } return function piped(input) { return fns.reduce(function (prev, fn) { return fn(prev); }, input); }; } var Observable = (function () { function Observable(subscribe) { if (subscribe) { this._subscribe = subscribe; } } Observable.prototype.lift = function (operator) { var observable = new Observable(); observable.source = this; observable.operator = operator; return observable; }; Observable.prototype.subscribe = function (observerOrNext, error, complete) { var _this = this; var subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete); errorContext(function () { var _a = _this, operator = _a.operator, source = _a.source; subscriber.add(operator ? operator.call(subscriber, source) : source ? _this._subscribe(subscriber) : _this._trySubscribe(subscriber)); }); return subscriber; }; Observable.prototype._trySubscribe = function (sink) { try { return this._subscribe(sink); } catch (err) { sink.error(err); } }; Observable.prototype.forEach = function (next, promiseCtor) { var _this = this; promiseCtor = getPromiseCtor(promiseCtor); return new promiseCtor(function (resolve, reject) { var subscriber = new SafeSubscriber({ next: function (value) { try { next(value); } catch (err) { reject(err); subscriber.unsubscribe(); } }, error: reject, complete: resolve, }); _this.subscribe(subscriber); }); }; Observable.prototype._subscribe = function (subscriber) { var _a; return (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber); }; Observable.prototype[observable] = function () { return this; }; Observable.prototype.pipe = function () { var operations = []; for (var _i = 0; _i < arguments.length; _i++) { operations[_i] = arguments[_i]; } return pipeFromArray(operations)(this); }; Observable.prototype.toPromise = function (promiseCtor) { var _this = this; promiseCtor = getPromiseCtor(promiseCtor); return new promiseCtor(function (resolve, reject) { var value; _this.subscribe(function (x) { return (value = x); }, function (err) { return reject(err); }, function () { return resolve(value); }); }); }; Observable.create = function (subscribe) { return new Observable(subscribe); }; return Observable; }()); function getPromiseCtor(promiseCtor) { var _a; return (_a = promiseCtor !== null && promiseCtor !== void 0 ? promiseCtor : config.Promise) !== null && _a !== void 0 ? _a : Promise; } function isObserver(value) { return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete); } function isSubscriber(value) { return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value)); } var ObjectUnsubscribedError = createErrorClass(function (_super) { return function ObjectUnsubscribedErrorImpl() { _super(this); this.name = 'ObjectUnsubscribedError'; this.message = 'object unsubscribed'; }; }); var Subject = (function (_super) { __extends(Subject, _super); function Subject() { var _this = _super.call(this) || this; _this.closed = false; _this.currentObservers = null; _this.observers = []; _this.isStopped = false; _this.hasError = false; _this.thrownError = null; return _this; } Subject.prototype.lift = function (operator) { var subject = new AnonymousSubject(this, this); subject.operator = operator; return subject; }; Subject.prototype._throwIfClosed = function () { if (this.closed) { throw new ObjectUnsubscribedError(); } }; Subject.prototype.next = function (value) { var _this = this; errorContext(function () { var e_1, _a; _this._throwIfClosed(); if (!_this.isStopped) { if (!_this.currentObservers) { _this.currentObservers = Array.from(_this.observers); } try { for (var _b = __values(_this.currentObservers), _c = _b.next(); !_c.done; _c = _b.next()) { var observer = _c.value; observer.next(value); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } }); }; Subject.prototype.error = function (err) { var _this = this; errorContext(function () { _this._throwIfClosed(); if (!_this.isStopped) { _this.hasError = _this.isStopped = true; _this.thrownError = err; var observers = _this.observers; while (observers.length) { observers.shift().error(err); } } }); }; Subject.prototype.complete = function () { var _this = this; errorContext(function () { _this._throwIfClosed(); if (!_this.isStopped) { _this.isStopped = true; var observers = _this.observers; while (observers.length) { observers.shift().complete(); } } }); }; Subject.prototype.unsubscribe = function () { this.isStopped = this.closed = true; this.observers = this.currentObservers = null; }; Object.defineProperty(Subject.prototype, "observed", { get: function () { var _a; return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0; }, enumerable: false, configurable: true }); Subject.prototype._trySubscribe = function (subscriber) { this._throwIfClosed(); return _super.prototype._trySubscribe.call(this, subscriber); }; Subject.prototype._subscribe = function (subscriber) { this._throwIfClosed(); this._checkFinalizedStatuses(subscriber); return this._innerSubscribe(subscriber); }; Subject.prototype._innerSubscribe = function (subscriber) { var _this = this; var _a = this, hasError = _a.hasError, isStopped = _a.isStopped, observers = _a.observers; if (hasError || isStopped) { return EMPTY_SUBSCRIPTION; } this.currentObservers = null; observers.push(subscriber); return new Subscription(function () { _this.currentObservers = null; arrRemove(observers, subscriber); }); }; Subject.prototype._checkFinalizedStatuses = function (subscriber) { var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, isStopped = _a.isStopped; if (hasError) { subscriber.error(thrownError); } else if (isStopped) { subscriber.complete(); } }; Subject.prototype.asObservable = function () { var observable = new Observable(); observable.source = this; return observable; }; Subject.create = function (destination, source) { return new AnonymousSubject(destination, source); }; return Subject; }(Observable)); var AnonymousSubject = (function (_super) { __extends(AnonymousSubject, _super); function AnonymousSubject(destination, source) { var _this = _super.call(this) || this; _this.destination = destination; _this.source = source; return _this; } AnonymousSubject.prototype.next = function (value) { var _a, _b; (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.next) === null || _b === void 0 ? void 0 : _b.call(_a, value); }; AnonymousSubject.prototype.error = function (err) { var _a, _b; (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.call(_a, err); }; AnonymousSubject.prototype.complete = function () { var _a, _b; (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.complete) === null || _b === void 0 ? void 0 : _b.call(_a); }; AnonymousSubject.prototype._subscribe = function (subscriber) { var _a, _b; return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : EMPTY_SUBSCRIPTION; }; return AnonymousSubject; }(Subject)); var BehaviorSubject = (function (_super) { __extends(BehaviorSubject, _super); function BehaviorSubject(_value) { var _this = _super.call(this) || this; _this._value = _value; return _this; } Object.defineProperty(BehaviorSubject.prototype, "value", { get: function () { return this.getValue(); }, enumerable: false, configurable: true }); BehaviorSubject.prototype._subscribe = function (subscriber) { var subscription = _super.prototype._subscribe.call(this, subscriber); !subscription.closed && subscriber.next(this._value); return subscription; }; BehaviorSubject.prototype.getValue = function () { var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, _value = _a._value; if (hasError) { throw thrownError; } this._throwIfClosed(); return _value; }; BehaviorSubject.prototype.next = function (value) { _super.prototype.next.call(this, (this._value = value)); }; return BehaviorSubject; }(Subject)); class DisposableObservable { #rxjs; constructor(rxjs) { this.#rxjs = rxjs; } subscribe(callback) { const subscription = this.#rxjs.subscribe(callback); const disposable = { dispose() { subscription.unsubscribe(); } }; return disposable; } } class Variable { #bs; // readonly #options: VariableOptions<T>; // eslint-disable-next-line @typescript-eslint/no-unused-vars constructor(bs, options = {}) { this.#bs = bs; // this.#options = options; } get() { return this.#bs.getValue(); } set(newValue) { // It appears that we need the first value for initialization. this.#bs.next(newValue); /* const oldValue = this.#bs.getValue(); if (newValue !== oldValue) { this.#bs.next(newValue); } else { if (this.#attributes.equals) { if (this.#attributes.equals(newValue, oldValue)) { // Do nothing. } else { this.#bs.next(newValue); } } } */ } asObservable() { return new DisposableObservable(this.#bs.asObservable()); } } exports("Variable", Variable); function variable(initialValue, options = {}) { const bs = new BehaviorSubject(initialValue); return new Variable(bs, options); } const abs = Math.abs; /** * @hidden * @param n * @param v * @returns */ function makeColumnVector(n, v) { const a = []; for (let i = 0; i < n; i++) { a.push(v); } return a; } /** * @hidden */ function rowWithMaximumInColumn(A, column, N) { let biggest = abs(A[column][column]); let maxRow = column; for (let row = column + 1; row < N; row++) { if (abs(A[row][column]) > biggest) { biggest = abs(A[row][column]); maxRow = row; } } return maxRow; } /** * @hidden */ function swapRows(A, i, j, N) { const colLength = N + 1; for (let column = i; column < colLength; column++) { const temp = A[j][column]; A[j][column] = A[i][column]; A[i][column] = temp; } } /** * @hidden * @param A * @param i * @param N */ function makeZeroBelow(A, i, N) { for (let row = i + 1; row < N; row++) { const c = -A[row][i] / A[i][i]; for (let column = i; column < N + 1; column++) { if (i === column) { A[row][column] = 0; } else { A[row][column] += c * A[i][column]; } } } } /** * @hidden * @param A * @param N * @returns */ function solve(A, N) { const x = makeColumnVector(N, 0); for (let i = N - 1; i > -1; i--) { x[i] = A[i][N] / A[i][i]; for (let k = i - 1; k > -1; k--) { A[k][N] -= A[k][i] * x[i]; } } return x; } /** * Gaussian elimination * Ax = b * @hidden * * @param A an array containing the rows of A, where each row is a number array. * @param b an array containing the rows of b, where each row is a number. * @returns x an array containing the rows of x, where each row is a number. */ function gauss(A, b) { const N = A.length; for (let i = 0; i < N; i++) { const Ai = A[i]; const bi = b[i]; Ai.push(bi); } for (let j = 0; j < N; j++) { swapRows(A, j, rowWithMaximumInColumn(A, j, N), N); makeZeroBelow(A, j, N); } return solve(A, N); } const sqrt = Math.sqrt; /** * Sets this multivector to a rotor representing a rotation from a to b. * R = (|b||a| + b * a) / sqrt(2 * |b||a|(|b||a| + b << a)) * Returns undefined (void 0) if the vectors are anti-parallel. * * @param a The 'from' vector. * @param b The 'to' vector. * @param m The output multivector. */ function rotorFromDirections(a, b, m) { const ax = a.x; const ay = a.y; const bx = b.x; const by = b.y; const aa = ax * ax + ay * ay; const absA = sqrt(aa); const bb = bx * bx + by * by; const absB = sqrt(bb); const BA = absB * absA; const dotBA = ax * bx + ay * by; const denom = sqrt(2 * (bb * aa + BA * dotBA)); if (denom !== 0) { const B = ay * bx - ax * by; m.set(0, 0, (BA + dotBA) / denom, B / denom); } } function is_zero_vector(v) { return v.x === 0 && v.y === 0; } function is_zero_bivector(m) { return m.b === 0; } function is_zero_multivector(m) { return is_zero_vector(m) && is_zero_bivector(m) && m.a === 0 && m.b === 0; } /** * Sentinel value to indicate that the Geometric is not locked. * UNLOCKED is in the range -1 to 0. * */ const UNLOCKED = -1 * Math.random(); /** * Sets the lock on the multivector argument and returns the same argument. * This is a convenience function for the dunder (double underscore) methods. * All dunder methods should return locked values. * */ function lock(m) { m.lock(); return m; } /** * */ function isScalar(m) { return m.x === 0 && m.y === 0 && m.b === 0; } function equalsValue$1(P, Q) { return P[0] === Q[0] && P[1] === Q[1] && P[2] === Q[2] && P[3] === Q[3]; } const COORD_A = 0; const COORD_X = 1; const COORD_Y = 2; const COORD_B = 3; function ensure_mutable(mv) { if (mv.isMutable()) { return mv; } else { return mv.clone(); } } function vector_from_like(like) { if (like instanceof G20) { return ensure_mutable(like); } else if (Array.isArray(like)) { return G20.vector(like[0], like[1]); } else { return null; } } function spinor_from_like(like) { if (like instanceof G20) { return ensure_mutable(like); } else if (Array.isArray(like)) { return G20.spinor(like[0], like[1]); } else { return null; } } /** * A multivector for two dimensions with a Euclidean metric. */ class G20 { /** * Contains the value that is currently stored in the signal (in the zeroth index of this array). * This backing store exists because 1) the signal implementation we are using does not support * mutation, and 2) we want this multivector to also be observable with events that only happen on * changes, and 3) we want to avoid taxing the Garbage Collector. */ #signalValue = [ [0, 0, 0, 0], [0, 0, 0, 0] ]; /** * The underlying data that makes this multivector into a signal. * The get method fo this signal MUST be called when accessing the coordinates (a, x, y, and b), * and MUST NOT be called when mutating this multivector. */ #signal = signal(this.#signalValue[0], { equals: equalsValue$1 }); #lock = UNLOCKED; #change = variable(this); change$ = this.#change.asObservable(); constructor(x = 0, y = 0, a = 0, b = 0) { this.set(x, y, a, b); } static scalar(a) { return new G20(0, 0, a, 0); } static bivector(b) { return new G20(0, 0, 0, b); } static spinor(a, b) { return new G20(0, 0, a, b); } static vector(x, y) { return new G20(x, y, 0, 0); } /** * Determines whether this multivector is locked. * If the multivector is in the unlocked state then it is mutable. * If the multivector is in the locked state then it is immutable. */ isLocked() { return this.#lock !== UNLOCKED; } isMutable() { return this.#lock === UNLOCKED; } /** * Locks this multivector (preventing any further mutation), * and returns a token that may be used to unlock it. */ lock() { if (this.#lock !== UNLOCKED) { throw new Error("already locked"); } else { this.#lock = Math.random(); return this.#lock; } } /** * Unlocks this multivector (allowing mutation), * using a token that was obtained from a preceding lock method call. */ unlock(token) { if (this.#lock === UNLOCKED) { throw new Error("not locked"); } else if (this.#lock === token) { this.#lock = UNLOCKED; return this; } else { throw new Error("unlock denied"); } } get a() { return this.#signal.get()[COORD_A]; } set a(a) { if (typeof a === "number") { const coords = this.#signalValue[0]; const old_a = coords[COORD_A]; if (a !== old_a) { const x = coords[COORD_X]; const y = coords[COORD_Y]; const b = coords[COORD_B]; this.set(x, y, a, b); } } } get x() { return this.#signal.get()[COORD_X]; } set x(x) { if (typeof x === "number") { const coords = this.#signalValue[0]; const old_x = coords[COORD_X]; if (x !== old_x) { const a = coords[COORD_A]; const b = coords[COORD_B]; const y = coords[COORD_Y]; this.set(x, y, a, b); } } } get y() { return this.#signal.get()[COORD_Y]; } set y(y) { if (typeof y === "number") { const coords = this.#signalValue[0]; const old_y = coords[COORD_Y]; if (y !== old_y) { const x = coords[COORD_X]; const a = coords[COORD_A]; const b = coords[COORD_B]; this.set(x, y, a, b); } } } get b() { return this.#signal.get()[COORD_B]; } set b(b) { if (typeof b === "number") { const coords = this.#signalValue[0]; const old_b = coords[COORD_B]; if (b !== old_b) { const x = coords[COORD_X]; const y = coords[COORD_Y]; const a = coords[COORD_A]; this.set(x, y, a, b);