@bitbybit-dev/base
Version:
Bit By Bit Developers Base CAD Library to Program Geometry
152 lines (151 loc) • 5.94 kB
JavaScript
export class GeometryHelper {
constructor() {
this.getArrayDepth = (value) => {
return Array.isArray(value) ?
1 + Math.max(...value.map(this.getArrayDepth)) :
0;
};
}
transformControlPoints(transformation, transformedControlPoints) {
const transformationArrays = this.getFlatTransformations(transformation);
transformationArrays.forEach(transform => {
transformedControlPoints = this.transformPointsByMatrixArray(transformedControlPoints, transform);
});
return transformedControlPoints;
}
getFlatTransformations(transformation) {
let transformationArrays = [];
if (this.getArrayDepth(transformation) === 3) {
transformation.forEach(transform => {
transformationArrays.push(...transform);
});
}
else {
transformationArrays = transformation;
}
return transformationArrays;
}
transformPointsByMatrixArray(points, transform) {
return this.transformPointsCoordinates(points, transform);
}
transformPointsCoordinates(points, transform) {
const transformedPoints = [];
for (const pt of points) {
const transformedVector = this.transformCoordinates(pt[0], pt[1], pt[2], transform);
transformedPoints.push(transformedVector);
}
return transformedPoints;
}
// 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.
removeConsecutiveVectorDuplicates(vectors, checkFirstAndLast = true, tolerance = 1e-7) {
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, 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, 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;
}
removeConsecutivePointDuplicates(points, checkFirstAndLast = true, tolerance = 1e-7) {
const pointsRemaining = [];
if (points.length > 1) {
for (let i = 1; i < points.length; i++) {
const currentPoint = points[i];
const previousPoint = points[i - 1];
if (!this.arePointsTheSame(currentPoint, previousPoint, tolerance)) {
pointsRemaining.push(previousPoint);
}
if (i === points.length - 1) {
pointsRemaining.push(currentPoint);
}
}
if (checkFirstAndLast) {
const firstPoint = pointsRemaining[0];
const lastPoint = pointsRemaining[pointsRemaining.length - 1];
if (this.arePointsTheSame(firstPoint, lastPoint, tolerance)) {
pointsRemaining.pop();
}
}
}
else if (points.length === 1) {
pointsRemaining.push(...points);
}
return pointsRemaining;
}
arePointsTheSame(pointA, pointB, tolerance) {
let result = false;
if (pointA.length === 2 && pointB.length === 2) {
if (this.approxEq(pointA[0], pointB[0], tolerance) &&
this.approxEq(pointA[1], pointB[1], tolerance)) {
result = true;
}
}
else if (pointA.length === 3 && pointB.length === 3) {
if (this.approxEq(pointA[0], pointB[0], tolerance) &&
this.approxEq(pointA[1], pointB[1], tolerance) &&
this.approxEq(pointA[2], pointB[2], tolerance)) {
result = true;
}
}
return result;
}
transformCoordinates(x, y, z, transformation) {
const m = transformation;
const rx = x * m[0] + y * m[4] + z * m[8] + m[12];
const ry = x * m[1] + y * m[5] + z * m[9] + m[13];
const rz = x * m[2] + y * m[6] + z * m[10] + m[14];
const rw = 1 / (x * m[3] + y * m[7] + z * m[11] + m[15]);
const newx = rx * rw;
const newy = ry * rw;
const newz = rz * rw;
return [newx, newy, newz];
}
}