jakke-graphics-ts
Version:
My common graphics utils for building my aec apps.
191 lines • 8.23 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LineEvaluation = void 0;
const vectorUtils_1 = require("./vectorUtils");
const TOLERANCE_LINE_EVALUATION = 1e-6;
/**
* Get point on line which is distanced from given distance.
* @param line Endpoints of line.
* @param dist Distance from endpoint.
* @param fromStart When true, anchor point will be start of line. Otherwise, end of line.
* @returns {Vertex3d} Point
*/
function getPointOnLine(line, dist, fromStart = true) {
const { p0, p1 } = line;
const lineVector = vectorUtils_1.VectorUtils.subtract(p1, p0);
const lineDirection = vectorUtils_1.VectorUtils.chain(lineVector).normalize().value();
const moveVector = vectorUtils_1.VectorUtils.scale(lineDirection, dist);
const anchor = fromStart ? p0 : p1;
const point = vectorUtils_1.VectorUtils.add(anchor, moveVector);
return point;
}
/**
* Get intersection point from lines.
* @param li0 First line of lines.
* @param li1 Second line of lines.
* @param fromExtended When it's true, intersection will be calculated including extended lines of li0, li1. Otherwise, only within li0, li1 boundary.
* @returns When the intersection exists, result will be true and pt will be that point. Otherwise, result false and message will include the reason of it.
*/
function getIntersection(li0, li1, fromExtended = false) {
if (vectorUtils_1.VectorUtils.isParallelLines(li0, li1))
return { result: false, message: "Parallel or same Lines" };
// Projection on XY Plane
const p1p3 = {
x: li1.p1.x - li0.p1.x,
y: li1.p1.y - li0.p1.y,
z: 0
};
const d0 = {
x: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li0.p1, li0.p0)).x,
y: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li0.p1, li0.p0)).y,
z: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li0.p1, li0.p0)).z,
};
const d1 = {
x: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li1.p1, li1.p0)).x,
y: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li1.p1, li1.p0)).y,
z: vectorUtils_1.VectorUtils.normalize(vectorUtils_1.VectorUtils.subtract(li1.p1, li1.p0)).z,
};
const d0PlaneXY = vectorUtils_1.VectorUtils.normalize({
x: d0.x,
y: d0.y,
z: 0
});
const d1PlaneXY = vectorUtils_1.VectorUtils.normalize({
x: d1.x,
y: d1.y,
z: 0
});
const det = -(d0PlaneXY.x * d1PlaneXY.y) + (d1PlaneXY.x * d0PlaneXY.y);
if (Math.abs(det) < TOLERANCE_LINE_EVALUATION) {
return { result: false, message: "Det is zero (parallel lines)" };
}
const dx = p1p3.x;
const dy = p1p3.y;
const t = -((d1PlaneXY.y * dx) - (d1PlaneXY.x * dy)) / det;
const u = -((d0PlaneXY.y * dx) - (d0PlaneXY.x * dy)) / det;
// Move ptQ at plane (z = li0.p0.z);
const ptLi0StartOnXY = {
x: li0.p0.x,
y: li0.p0.y,
z: 0
};
const ptLi0EndOnXY = {
x: li0.p1.x,
y: li0.p1.y,
z: 0
};
// Move ptR at plane (z = li1.p0.z)
const ptLi1StartOnXY = {
x: li1.p0.x,
y: li1.p0.y,
z: 0
};
const ptLi1EndOnXY = {
x: li1.p1.x,
y: li1.p1.y,
z: 0
};
const ptQ = vectorUtils_1.VectorUtils.add(ptLi0EndOnXY, vectorUtils_1.VectorUtils.scale(d0PlaneXY, t));
const ptR = vectorUtils_1.VectorUtils.add(ptLi1EndOnXY, vectorUtils_1.VectorUtils.scale(d1PlaneXY, u));
const dist = vectorUtils_1.VectorUtils.getDist(ptQ, ptR);
if (dist > TOLERANCE_LINE_EVALUATION)
return { result: false, message: "Each points on XY Plane is not same." };
// Place ptQ on li0
const tLi0 = vectorUtils_1.VectorUtils.dot(vectorUtils_1.VectorUtils.subtract(ptQ, ptLi0StartOnXY), d0PlaneXY);
const ratioLi0 = vectorUtils_1.VectorUtils.getDist(li0.p1, li0.p0) / vectorUtils_1.VectorUtils.getDist(ptLi0EndOnXY, ptLi0StartOnXY);
const vLi0 = tLi0 * ratioLi0;
const ptQ2 = {
x: li0.p0.x + vLi0 * d0.x,
y: li0.p0.y + vLi0 * d0.y,
z: li0.p0.z + vLi0 * d0.z
};
// Place ptR on li1
const tLi1 = vectorUtils_1.VectorUtils.dot(vectorUtils_1.VectorUtils.subtract(ptR, ptLi1StartOnXY), d1PlaneXY);
const ratioLi1 = vectorUtils_1.VectorUtils.getDist(li1.p1, li1.p0) / vectorUtils_1.VectorUtils.getDist(ptLi1EndOnXY, ptLi1StartOnXY);
const vLi1 = tLi1 * ratioLi1;
const ptR2 = {
x: li1.p0.x + vLi1 * d1.x,
y: li1.p0.y + vLi1 * d1.y,
z: li1.p0.z + vLi1 * d1.z
};
if (vectorUtils_1.VectorUtils.getDist(ptQ2, ptR2) > TOLERANCE_LINE_EVALUATION)
return { result: false, message: "Two line's are on skew position." };
if (fromExtended) {
return { result: true, pt: ptQ2 };
}
else {
const paramPtQ2 = getParameterOnLine(li0.p0, li0.p1, ptQ2);
const paramPtR2 = getParameterOnLine(li1.p0, li1.p1, ptR2);
if ((-TOLERANCE_LINE_EVALUATION <= paramPtQ2 && paramPtQ2 <= 1 + TOLERANCE_LINE_EVALUATION) &&
(-TOLERANCE_LINE_EVALUATION <= paramPtR2 && paramPtR2 <= 1 + TOLERANCE_LINE_EVALUATION)) {
return { result: true, pt: ptQ2 };
}
else {
return { result: false, message: "One of the points are placed on outside the line's domain." };
}
}
}
/**
* Evaluate the parameter of given line and point.
* @param p0 Start point of Line
* @param p1 End point of Line
* @param ptTest Point to test
* @returns {number|undefined}
* When the given point is on the line between endpoints, the result will be 0 ~ 1.
* When it is on the line but outside the endpoints, the result will be negative float or larger than 1.
* When it is determined that the point actually not placed on the line, it will return undefined.
*/
function getParameterOnLine(p0, p1, ptTest) {
const direction = vectorUtils_1.VectorUtils.subtract(p1, p0);
const toTest = vectorUtils_1.VectorUtils.subtract(ptTest, p0);
const lengthSquared = vectorUtils_1.VectorUtils.dot(direction, direction); // |d|^2
if (lengthSquared === 0)
return 0; // zero length line
const t = vectorUtils_1.VectorUtils.dot(toTest, direction) / lengthSquared;
return t;
}
/**
* Find foot point on line passing, which has direction as given.
* @param direction Direction of line.
* @param pt Point to foot on line.
* @returns If you set direction as zero vector, it will return origin and param as 0.
*/
function getFootPointOnDirection(direction, pt) {
if (vectorUtils_1.VectorUtils.getSize(direction) < TOLERANCE_LINE_EVALUATION)
return;
const norm = vectorUtils_1.VectorUtils.normalize(direction);
const dSize = vectorUtils_1.VectorUtils.getSize(norm);
const dot = vectorUtils_1.VectorUtils.dot(norm, pt);
const t = dot / Math.pow(dSize, 2);
return { pt: vectorUtils_1.VectorUtils.scale(norm, t), t };
}
/**
* Find foot point on line.
* @param line Line passing two points.
* @param pt Point to foot on line.
* @returns If you set each point of the line which has almost same coordinate each other, it will return origin and param as 0.
*/
function getFootPointOnLine(line, pt) {
const direction = vectorUtils_1.VectorUtils.subtract(line.p1, line.p0);
if (vectorUtils_1.VectorUtils.getSize(direction) < TOLERANCE_LINE_EVALUATION)
return;
const anchor = line.p0;
const ptMoved = vectorUtils_1.VectorUtils.subtract(pt, anchor);
const norm = vectorUtils_1.VectorUtils.normalize(direction);
const dSize = vectorUtils_1.VectorUtils.getSize(norm);
if (dSize === 0)
return;
const dot = vectorUtils_1.VectorUtils.dot(norm, ptMoved);
const t = dot / vectorUtils_1.VectorUtils.getSize(direction);
const ptOnMovedLine = vectorUtils_1.VectorUtils.scale(norm, dot);
const ptFooting = vectorUtils_1.VectorUtils.add(ptOnMovedLine, anchor);
return { pt: ptFooting, t };
}
exports.LineEvaluation = {
getPointOnLine,
getIntersection,
getParameterOnLine,
getFootPointOnLine,
getFootPointOnDirection
};
//# sourceMappingURL=lineEvaluationUtils.js.map