export class VectorHelperService {
    constructor() {
        this.tolerance = 0.00001;
    }
    degToRad(degrees) {
        return degrees * (Math.PI / 180);
    }
    remap(value, from1, to1, from2, to2) {
        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, tolerance = 1e-7) {
        const cleanVectors = [];
        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, checkFirstAndLast = true) {
        const vectorsRemaining = [];
        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];
                if (this.vectorsTheSame(firstVector, lastVector, this.tolerance)) {
                    vectorsRemaining.pop();
                }
            }
        }
        else if (vectors.length === 1) {
            vectorsRemaining.push(...vectors);
        }
        return vectorsRemaining;
    }
    vectorsTheSame(vec1, vec2, tolerance) {
        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, num2, tolerance) {
        const res = Math.abs(num1 - num2) < tolerance;
        return res;
    }
    averageVector(vectors) {
        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) {
        return Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0));
    }
    normalize(vector) {
        const magnitude = this.magnitude(vector);
        return vector.map(v => v / magnitude);
    }
    translatePoint(point, vector, distance) {
        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, vector2) {
        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, point2) {
        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);
    }
}
