OpenHPS/openhps-core

View on GitHub
src/data/position/RelativePosition.ts

Summary

Maintainability
B
6 hrs
Test Coverage
import { TimeService } from '../../service/TimeService';
import { Unit } from '../../utils';
import { DataSerializer } from '../DataSerializer';
import { SerializableMember, SerializableObject, NumberType } from '../decorators';
import { Accuracy } from '../values/Accuracy';
import { Accuracy1D } from '../values/Accuracy1D';
import { Position } from './Position';

/**
 * Relative position to another reference object or space.
 * @category Position
 */
@SerializableObject()
export class RelativePosition<T = number, U extends Unit = Unit> implements Position<U> {
    /**
     * Position recording timestamp
     */
    @SerializableMember({
        index: true,
        numberType: NumberType.LONG,
    })
    timestamp: number = TimeService.now();
    /**
     * Reference object UID that this location is relative to
     */
    @SerializableMember()
    referenceObjectUID: string;
    @SerializableMember()
    referenceObjectType: string;
    @SerializableMember()
    referenceValue: T;
    @SerializableMember({
        name: 'accuracy',
    })
    private _accuracy: Accuracy<U, any>;
    @SerializableMember({
        name: 'probability',
        numberType: NumberType.DECIMAL,
    })
    private _probability: number;
    private _defaultUnit: U;
    @SerializableMember(() => Unit)
    unit: U;

    /**
     * Get the position probability
     * @returns {number} Probability between 0 and 1
     */
    get probability(): number {
        if (!this._probability) {
            return 1 / this.accuracy.valueOf();
        }
        return this._probability;
    }

    set probability(value: number) {
        if (value > 1 || value < 0) {
            throw new Error(`${this.constructor.name} should be between 0 and 1.`);
        }
        this._probability = value;
    }

    /**
     * Position accuracy
     * @returns {Accuracy} Position accuracy
     */
    get accuracy(): Accuracy<U, any> {
        if (!this._accuracy) {
            this._accuracy = new Accuracy1D(1, this._defaultUnit);
        }
        return this._accuracy;
    }

    set accuracy(value: Accuracy<U, any>) {
        if (!value) {
            throw new Error(`Accuracy can not be undefined!`);
        }
        this._accuracy = value;
    }

    constructor(referenceObject?: any, value?: T, unit?: U) {
        if (referenceObject !== undefined) {
            if (referenceObject instanceof String || typeof referenceObject === 'string') {
                this.referenceObjectUID = referenceObject as string;
            } else {
                this.referenceObjectType = referenceObject.constructor.name;
                this.referenceObjectUID = referenceObject.uid;
            }
        }
        this._defaultUnit = unit || (Unit.UNKNOWN as U);
        this.unit = unit;
        this.referenceValue = value;
    }

    /**
     * Set the accuracy of the absolute position
     * @param {number | Accuracy} accuracy Accuracy object or number
     * @param {Unit} [unit] Optional unit
     * @returns {RelativePosition} instance
     */
    setAccuracy(accuracy: number | Accuracy<U, any>, unit?: U): this {
        if (typeof accuracy === 'number') {
            this.accuracy = new Accuracy1D(accuracy, unit || this._defaultUnit);
        } else {
            this.accuracy = accuracy;
        }
        return this;
    }

    equals(position: this): boolean {
        return this.timestamp === position.timestamp;
    }

    /**
     * Clone the position
     * @returns {RelativePosition} Cloned relative position
     */
    clone(): this {
        return DataSerializer.clone(this);
    }
}