UNPKG

@mlightcad/geometry-engine

Version:

The geometry-engine package provides comprehensive geometric entities, mathematical operations, and transformations for 2D and 3D space. This package mimics AutoCAD ObjectARX's AcGe (Geometry) classes and provides the mathematical foundation for CAD opera

213 lines 8.42 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { AcGePoint2d } from '../math/AcGePoint2d'; import { AcGeShape2d } from './AcGeShape2d'; /** * Abstract base class for all 2d curves. Any class that is derived from this class represents * a 2d curve. */ var AcGeCurve2d = /** @class */ (function (_super) { __extends(AcGeCurve2d, _super); function AcGeCurve2d() { var _this = _super.call(this) || this; _this.arcLengthDivisions = 100; return _this; } Object.defineProperty(AcGeCurve2d.prototype, "startPoint", { /** * Start point of this curve. If the curve is closed, coordinates of start point will be equal to coordinates * of end point. */ get: function () { return this.getPoint(0); }, enumerable: false, configurable: true }); Object.defineProperty(AcGeCurve2d.prototype, "endPoint", { /** * End point of this curve. If the curve is closed, coordinates of start point will be equal to coordinates * of end point. */ get: function () { return this.getPoint(1); }, enumerable: false, configurable: true }); Object.defineProperty(AcGeCurve2d.prototype, "length", { /** * Length of this curve. */ get: function () { return this.getLength(); }, enumerable: false, configurable: true }); /** * Return the point for a given position on the curve according to the arc length. * @param t Input a position on the curve according to the arc length. Must be in the range [0, 1]. * @returns Return the point for a given position on the curve according to the arc length. */ AcGeCurve2d.prototype.getPoint = function (_t) { throw new Error('AcGeCurve2d: .getPoint() not implemented.'); }; /** * Return a point for a given position on the curve according to the arc length. * @param u Input a position on the curve according to the arc length. Must be in the range [0, 1]. * @returns Return a point for a given position on the curve according to the arc length. */ AcGeCurve2d.prototype.getPointAt = function (u) { var t = this.getUtoTmapping(u); return this.getPoint(t); }; /** * Return a set of divisions + 1 points using `getPoint(t)`. * @param divisions Input number of pieces to divide the curve into. Default is 5. * @returns Return a set of divisions + 1 points using `getPoint(t)` */ AcGeCurve2d.prototype.getPoints = function (divisions) { if (divisions === void 0) { divisions = 5; } var points = []; for (var d = 0; d <= divisions; d++) { points.push(this.getPoint(d / divisions)); } return points; }; /** * Return a set of divisions + 1 equi-spaced points using `getPointAt(u)`. * @param divisions Input number of pieces to divide the curve into. Default is 5. * @returns Return a set of divisions + 1 equi-spaced points using `getPointAt(u)`. */ AcGeCurve2d.prototype.getSpacedPoints = function (divisions) { if (divisions === void 0) { divisions = 5; } var points = []; for (var d = 0; d <= divisions; d++) { points.push(this.getPointAt(d / divisions)); } return points; }; /** * Get total curve arc length. * @returns Return total curve arc length. */ AcGeCurve2d.prototype.getLength = function () { var lengths = this.getLengths(); return lengths[lengths.length - 1]; }; /** * Get list of cumulative segment lengths. * @param divisions Input number of pieces to divide the curve into. * @returns Return list of cumulative segment lengths. */ AcGeCurve2d.prototype.getLengths = function (divisions) { if (divisions === void 0) { divisions = this.arcLengthDivisions; } var cache = []; var current, last = this.getPoint(0); var sum = 0; cache.push(0); for (var p = 1; p <= divisions; p++) { current = this.getPoint(p / divisions); sum += current.distanceTo(last); cache.push(sum); last = current; } return cache; }; /** * Given `u` in the range (0 .. 1), returns t also in the range ( 0 .. 1 ). `u` and `t` can then be used to * give you points which are equidistant from the ends of the curve, using `getPoint`. */ AcGeCurve2d.prototype.getUtoTmapping = function (u, distance) { var arcLengths = this.getLengths(); var i = 0; var il = arcLengths.length; var targetArcLength; // The targeted u distance value to get if (distance) { targetArcLength = distance; } else { targetArcLength = u * arcLengths[il - 1]; } // binary search for the index with largest value smaller than target u distance var low = 0, high = il - 1, comparison; while (low <= high) { i = Math.floor(low + (high - low) / 2); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats comparison = arcLengths[i] - targetArcLength; if (comparison < 0) { low = i + 1; } else if (comparison > 0) { high = i - 1; } else { high = i; break; // DONE } } i = high; if (arcLengths[i] === targetArcLength) { return i / (il - 1); } // we could get finer grain at lengths, or use simple interpolation between two points var lengthBefore = arcLengths[i]; var lengthAfter = arcLengths[i + 1]; var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points var segmentFraction = (targetArcLength - lengthBefore) / segmentLength; // add that fractional amount to t var t = (i + segmentFraction) / (il - 1); return t; }; /** * Return a unit vector tangent at `t`. If the derived curve does not implement its tangent derivation, * two points a small delta apart will be used to find its gradient which seems to give a reasonable * approximation. * @param t Input a position on the curve. Must be in the range [ 0, 1 ]. * @returns Return a unit vector tangent at `t`. */ AcGeCurve2d.prototype.getTangent = function (t) { var delta = 0.0001; var t1 = t - delta; var t2 = t + delta; // Capping in case of danger if (t1 < 0) t1 = 0; if (t2 > 1) t2 = 1; var pt1 = this.getPoint(t1); var pt2 = this.getPoint(t2); var tangent = new AcGePoint2d(); tangent.copy(pt2).sub(pt1).normalize(); return tangent; }; /** * Return tangent at a point which is equidistant to the ends of the curve from the point given in * `getTangent`. * @param u Input a position on the curve according to the arc length. Must be in the range [0, 1]. * @returns Return tangent at a point which is equidistant to the ends of the curve from the point * given in `getTangent`. */ AcGeCurve2d.prototype.getTangentAt = function (u) { var t = this.getUtoTmapping(u); return this.getTangent(t); }; return AcGeCurve2d; }(AcGeShape2d)); export { AcGeCurve2d }; //# sourceMappingURL=AcGeCurve2d.js.map