All files / lib/api vector-helper.service.ts

93.44% Statements 57/61
90% Branches 18/20
94.73% Functions 18/19
92.59% Lines 50/54

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110    18x       26x       1188x         51x 51x   5736x 385x     51x         3x 3x 2x 293x 293x 293x 272x   293x 2x     2x 1x 1x 1x 1x     1x 1x   3x       8800x 8800x 1x   8799x 8799x 12132x 7901x 7901x       8799x       12132x 12132x       1x 9x   3x       9x       1x 3x       1x 1x 1x 1x                     62x 62x 62x 62x    
export class VectorHelperService {
 
    private readonly tolerance = 0.00001;
 
 
    degToRad(degrees: number) {
        return degrees * (Math.PI / 180);
    }
 
    remap(value: number, from1: number, to1: number, from2: number, to2: number): number {
        return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
    }
 
    // Algorithm works with arbitrary length numeric vectors. This algorithm is more costly for longer arrays of vectors
    removeAllDuplicateVectors(vectors: number[][], tolerance = 1e-7): number[][] {
        const cleanVectors: number[][] = [];
        vectors.forEach(vector => {
            // when there are no vectors in cleanVectors array that match the current vector, push it in.
            if (!cleanVectors.some(s => this.vectorsTheSame(vector, s, tolerance))) {
                cleanVectors.push(vector);
            }
        });
        return cleanVectors;
    }
 
    // Algorithm works with arbitrary length numeric vectors. 
    removeConsecutiveDuplicates(vectors: number[][], checkFirstAndLast = true): number[][] {
        const vectorsRemaining: number[][] = [];
        if (vectors.length > 1) {
            for (let i = 1; i < vectors.length; i++) {
                const currentVector = vectors[i];
                const previousVector = vectors[i - 1];
                if (!this.vectorsTheSame(currentVector, previousVector, this.tolerance)) {
                    vectorsRemaining.push(previousVector);
                }
                if (i === vectors.length - 1) {
                    vectorsRemaining.push(currentVector);
                }
            }
            if (checkFirstAndLast) {
                const firstVector = vectorsRemaining[0];
                const lastVector = vectorsRemaining[vectorsRemaining.length - 1];
                Eif (this.vectorsTheSame(firstVector, lastVector, this.tolerance)) {
                    vectorsRemaining.pop();
                }
            }
        } else Eif (vectors.length === 1) {
            vectorsRemaining.push(...vectors);
        }
        return vectorsRemaining;
    }
 
    vectorsTheSame(vec1: number[], vec2: number[], tolerance: number) {
        let result = false;
        if (vec1.length !== vec2.length) {
            return result;
        } else {
            result = true;
            for (let i = 0; i < vec1.length; i++) {
                if (!this.approxEq(vec1[i], vec2[i], tolerance)) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }
 
    approxEq(num1: number, num2: number, tolerance: number): boolean {
        const res = Math.abs(num1 - num2) < tolerance;
        return res;
    }
 
    averageVector(vectors: number[][]): number[] {
        const average = vectors.reduce((acc, val) => {
            return acc.map((a, i) => a + val[i]);
        }, [0, 0, 0]);
        return average.map(a => a / vectors.length);
    }
 
    magnitude(vector: number[]): number {
        return Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0));
    }
 
    normalize(vector: number[]): number[] {
        const magnitude = this.magnitude(vector);
        return vector.map(v => v / magnitude);
    }
 
    translatePoint(point: [number, number, number], vector: [number, number, number], distance: number): [number, number, number] {
        const x = point[0] + vector[0] * distance;
        const y = point[1] + vector[1] * distance;
        const z = point[2] + vector[2] * distance;
        return [x, y, z];
    }
 
    angleBetweenVectors(vector1: [number, number, number], vector2: [number, number, number]): number {
        const dotProduct = vector1[0] * vector2[0] + vector1[1] * vector2[1] + vector1[2] * vector2[2];
        const magnitude1 = this.magnitude(vector1);
        const magnitude2 = this.magnitude(vector2);
        return Math.acos(dotProduct / (magnitude1 * magnitude2));
    }
 
    distanceBetweenPoints(point1: [number, number, number], point2: [number, number, number]): number {
        const x = point2[0] - point1[0];
        const y = point2[1] - point1[1];
        const z = point2[2] - point1[2];
        return Math.sqrt(x * x + y * y + z * z);
    }
}