@js-draw/math
Version:
A math library for js-draw.
121 lines (120 loc) • 5.31 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _Triangle_sides;
import Abstract2DShape from './Abstract2DShape.mjs';
import LineSegment2 from './LineSegment2.mjs';
import Rect2 from './Rect2.mjs';
class Triangle extends Abstract2DShape {
/**
* @see {@link fromVertices}
*/
constructor(vertex1, vertex2, vertex3) {
super();
this.vertex1 = vertex1;
this.vertex2 = vertex2;
this.vertex3 = vertex3;
_Triangle_sides.set(this, undefined);
}
/**
* Creates a triangle from its three corners. Corners may be stored in a different
* order than given.
*/
static fromVertices(vertex1, vertex2, vertex3) {
return new Triangle(vertex1, vertex2, vertex3);
}
get vertices() {
return [this.vertex1, this.vertex2, this.vertex3];
}
map(mapping) {
return new Triangle(mapping(this.vertex1), mapping(this.vertex2), mapping(this.vertex3));
}
// Transform, treating this as composed of 2D points.
transformed2DBy(affineTransform) {
return this.map((vertex) => affineTransform.transformVec2(vertex));
}
// Transforms this by a linear transform --- verticies are treated as
// 3D points.
transformedBy(linearTransform) {
return this.map((vertex) => linearTransform.transformVec3(vertex));
}
/**
* Returns the sides of this triangle, as an array of `LineSegment2`s.
*
* The first side is from `vertex1` to `vertex2`, the next from `vertex2` to `vertex3`,
* and the last from `vertex3` to `vertex1`.
*/
getEdges() {
if (__classPrivateFieldGet(this, _Triangle_sides, "f")) {
return __classPrivateFieldGet(this, _Triangle_sides, "f");
}
const side1 = new LineSegment2(this.vertex1, this.vertex2);
const side2 = new LineSegment2(this.vertex2, this.vertex3);
const side3 = new LineSegment2(this.vertex3, this.vertex1);
const sides = [side1, side2, side3];
__classPrivateFieldSet(this, _Triangle_sides, sides, "f");
return sides;
}
intersectsLineSegment(lineSegment) {
const result = [];
for (const edge of this.getEdges()) {
edge.intersectsLineSegment(lineSegment).forEach((point) => result.push(point));
}
return result;
}
/** @inheritdoc */
containsPoint(point, epsilon = Abstract2DShape.smallValue) {
// Project `point` onto normals to each of this' sides.
// Uses the Separating Axis Theorem (https://en.wikipedia.org/wiki/Hyperplane_separation_theorem#Use_in_collision_detection)
const sides = this.getEdges();
for (const side of sides) {
const orthog = side.direction.orthog();
// Project all three vertices
// TODO: Performance can be improved here (two vertices will always have the same projection)
const projv1 = orthog.dot(this.vertex1);
const projv2 = orthog.dot(this.vertex2);
const projv3 = orthog.dot(this.vertex3);
const minProjVertex = Math.min(projv1, projv2, projv3);
const maxProjVertex = Math.max(projv1, projv2, projv3);
const projPoint = orthog.dot(point);
const inProjection = projPoint >= minProjVertex - epsilon && projPoint <= maxProjVertex + epsilon;
if (!inProjection) {
return false;
}
}
return true;
}
/**
* @returns the signed distance from `point` to the closest edge of this triangle.
*
* If `point` is inside `this`, the result is negative, otherwise, the result is
* positive.
*/
signedDistance(point) {
const sides = this.getEdges();
const distances = sides.map((side) => side.distance(point));
const distance = Math.min(...distances);
// If the point is in this' interior, signedDistance must return a negative
// number.
if (this.containsPoint(point, 0)) {
return -distance;
}
else {
return distance;
}
}
/** @inheritdoc */
getTightBoundingBox() {
return Rect2.bboxOf(this.vertices);
}
}
_Triangle_sides = new WeakMap();
export default Triangle;