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

350 lines 14.3 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 { AcCmErrors } from '@mlightcad/common'; import verb from 'verb-nurbs-web'; import { AcGeBox3d, AcGePoint3d } from '../math'; import { AcGeCurve3d } from './AcGeCurve3d'; import { AcGeNurbsCurve } from './AcGeNurbsCurve'; var AcGeSpline3d = /** @class */ (function (_super) { __extends(AcGeSpline3d, _super); function AcGeSpline3d(a, b, c, d, e) { var _this = _super.call(this) || this; // Count the number of arguments passed (including undefined) var argsLength = arguments.length; if (argsLength < 2 || argsLength > 5) { throw AcCmErrors.ILLEGAL_PARAMETERS; } // Default degree is 3 _this._degree = 3; _this._closed = false; if (!Array.isArray(b)) { // Constructor with fit points _this._fitPoints = a; _this._knotParameterization = b; // Handle degree and closed parameters for fit points constructor if (argsLength >= 3) { _this._degree = c || 3; } if (argsLength >= 4) { _this._closed = d; } // Validate minimum number of fit points for the specified degree if (_this._fitPoints.length < _this._degree + 1) { throw AcCmErrors.ILLEGAL_PARAMETERS; } var points = _this.toNurbsPoints(_this._fitPoints); _this._nurbsCurve = verb.geom.NurbsCurve.byPoints(points, _this._degree); _this._controlPoints = _this.toGePoints(_this._nurbsCurve.controlPoints()); } else { // Constructor with control points _this._controlPoints = a; // Determine if c is weights or degree based on type var weights = void 0; var degree = 3; var closed_1 = false; if (argsLength >= 3) { if (Array.isArray(c)) { // c is weights array weights = c; if (argsLength >= 4) { degree = d || 3; } if (argsLength >= 5) { closed_1 = e; } } else if (c !== undefined) { // c is degree (not undefined) degree = c || 3; if (argsLength >= 4) { closed_1 = d; } } } // Handle case where c is undefined but d might be degree if (c === undefined && argsLength >= 4) { degree = d || 3; if (argsLength >= 5) { closed_1 = e; } } _this._degree = degree; _this._closed = closed_1; // Validate minimum number of control points for the specified degree if (_this._controlPoints.length < _this._degree + 1) { throw AcCmErrors.ILLEGAL_PARAMETERS; } var points = _this.toVerbPoints(_this._controlPoints); _this._nurbsCurve = verb.geom.NurbsCurve.byKnotsControlPointsWeights(_this._degree, b, points, weights); } return _this; // Apply closed state if specified // if (this._closed) { // this.buildCurve() // } } /** * Build the NURBS curve using stored data */ AcGeSpline3d.prototype.buildCurve = function () { if (this._fitPoints && this._knotParameterization) { // Build from fit points if (this._closed) { var newFitPoints = AcGeNurbsCurve.createFitPointsForClosedCurve(this._fitPoints); var points = this.toNurbsPoints(newFitPoints); this._nurbsCurve = verb.geom.NurbsCurve.byPoints(points, this._degree); } else { // Create open curve from fit points var points = this.toNurbsPoints(this._fitPoints); this._nurbsCurve = verb.geom.NurbsCurve.byPoints(points, this._degree); } this._controlPoints = this.toGePoints(this._nurbsCurve.controlPoints()); } else if (this._controlPoints) { // Build from control points if (this._closed) { // Create closed curve from control points var newFitPoints = AcGeNurbsCurve.createFitPointsForClosedCurve(this._controlPoints); var points = this.toNurbsPoints(newFitPoints); this._nurbsCurve = verb.geom.NurbsCurve.byPoints(points, this._degree); this._controlPoints = this.toGePoints(this._nurbsCurve.controlPoints()); } else { // Create open curve from control points // Get knots and weights from the current NURBS curve var knots = this._nurbsCurve.knots(); var weights = this._nurbsCurve.weights(); var points = this.toVerbPoints(this._controlPoints); this._nurbsCurve = verb.geom.NurbsCurve.byKnotsControlPointsWeights(this._degree, knots, points, weights); } } }; /** * Set the closed property and rebuild the curve if necessary */ AcGeSpline3d.prototype.setClosed = function (closed) { if (this._closed === closed) { return; } this._closed = closed; this._boundingBoxNeedsUpdate = true; this.buildCurve(); }; Object.defineProperty(AcGeSpline3d.prototype, "degree", { /** * Degree of the spline to be created. */ get: function () { return this._degree; }, enumerable: false, configurable: true }); Object.defineProperty(AcGeSpline3d.prototype, "knotParameterization", { get: function () { return this._knotParameterization; }, enumerable: false, configurable: true }); Object.defineProperty(AcGeSpline3d.prototype, "startPoint", { /** * The start point of this spline */ get: function () { var knots = this._nurbsCurve.knots(); var degree = this._nurbsCurve.degree(); var startParam = knots[degree]; var startPoint = this._nurbsCurve.point(startParam); return new AcGePoint3d(startPoint[0], startPoint[1], startPoint[2]); }, enumerable: false, configurable: true }); Object.defineProperty(AcGeSpline3d.prototype, "endPoint", { /** * The end point of this spline */ get: function () { var knots = this._nurbsCurve.knots(); var degree = this._nurbsCurve.degree(); var endParam = knots[knots.length - degree - 1]; var endPoint = this._nurbsCurve.point(endParam); return new AcGePoint3d(endPoint[0], endPoint[1], endPoint[2]); }, enumerable: false, configurable: true }); Object.defineProperty(AcGeSpline3d.prototype, "length", { /** * @inheritdoc */ get: function () { return this._nurbsCurve.length(); }, enumerable: false, configurable: true }); /** * Return the value of the control point at position index in the list of control points. * If index is negative or more than the number of control points in the spline, then point * is set to the last control point. * @param index Input index (0 based) of point to get * @returns */ AcGeSpline3d.prototype.getFitPointAt = function (index) { if (!this._fitPoints) { throw new Error('No fit points in this spline'); } var length = this._fitPoints.length; var newIndex = index < 0 || index >= length ? length - 1 : index; var point = this._fitPoints[newIndex]; return { x: point.x, y: point.y, z: point.z || 0 }; }; /** * Return the value of the control point at position index in the list of control points. * If index is negative or more than the number of control points in the spline, then point * is set to the last control point. * @param index Input index (0 based) of point to get * @returns */ AcGeSpline3d.prototype.getControlPointAt = function (index) { var length = this._controlPoints.length; var newIndex = index < 0 || index >= length ? length - 1 : index; return this._controlPoints[newIndex]; }; /** * Divide this spline into the specified nubmer of points * those points as an array of points. * @param numPoints Input the nubmer of points returned * @returns Return an array of point */ AcGeSpline3d.prototype.getPoints = function (numPoints) { if (numPoints === void 0) { numPoints = 100; } var curve = this._nurbsCurve; var points = []; // Get the knot vector from the curve var knots = curve.knots(); // The valid parameter range is between knots[degree] and knots[knots.length - degree - 1] var degree = this._nurbsCurve.degree(); var startParam = knots[degree]; var endParam = knots[knots.length - degree - 1]; // Adjust step size for correct range var step = (endParam - startParam) / (numPoints - 1); for (var i = 0; i < numPoints; i++) { // For the last point, use endParam exactly to avoid floating-point issues var t = i === numPoints - 1 ? endParam : startParam + i * step; var point = curve.point(t); points.push(new AcGePoint3d(point[0], point[1], point[2])); } return points; }; AcGeSpline3d.prototype.getCurvePoints = function (curve, count) { var points = []; var knots = curve.knots(); // Get the knot vector from the curve // The valid parameter range is between knots[degree] and knots[knots.length - degree - 1] var startParam = knots[3]; var endParam = knots[knots.length - 4]; var step = (endParam - startParam) / (count - 1); // Adjust step size for correct range for (var i = 0; i < count; i++) { var t = startParam + i * step; // Map t to the correct parameter space points.push(curve.point(t)); // Sample the curve at the mapped parameter t } return points; }; /** * @inheritdoc */ AcGeSpline3d.prototype.calculateBoundingBox = function () { var points = this.getPoints(100); return new AcGeBox3d().setFromPoints(points); }; Object.defineProperty(AcGeSpline3d.prototype, "closed", { get: function () { return this._closed; }, set: function (value) { this.setClosed(value); }, enumerable: false, configurable: true }); /** * @inheritdoc */ AcGeSpline3d.prototype.transform = function (_matrix) { // TODO: Implement this method this._boundingBoxNeedsUpdate = true; return this; }; /** * Convert input points to points in NURBS format * @param points Input points to convert * @returns Return converted points */ AcGeSpline3d.prototype.toNurbsPoints = function (points) { var nurbsPoints = new Array(points.length); points.forEach(function (point, index) { nurbsPoints[index] = [point.x, point.y, point.z || 0]; }); return nurbsPoints; }; /** * Convert input points to points in verb-nurbs-web format * @param points Input points to convert * @returns Return converted points */ AcGeSpline3d.prototype.toVerbPoints = function (points) { var verbPoints = new Array(points.length); points.forEach(function (point, index) { verbPoints[index] = [point.x, point.y, point.z || 0]; }); return verbPoints; }; /** * Convert input points to points in geometry engine format * @param points Input points to convert * @returns Return converted points */ AcGeSpline3d.prototype.toGePoints = function (points) { var gePoints = new Array(points.length); points.forEach(function (point, index) { gePoints[index] = { x: point[0], y: point[1], z: point[2] }; }); return gePoints; }; /** * Create a closed spline from fit points using AcGeNurbsCurve.createClosedCurve * @param fitPoints - Array of fit points defining the curve * @param parameterization - Knot parameterization type for NURBS * @param degree - Optional degree of the spline (default: 3) * @returns A closed spline */ AcGeSpline3d.createClosedSpline = function (fitPoints, parameterization, degree) { if (parameterization === void 0) { parameterization = 'Uniform'; } if (degree === void 0) { degree = 3; } if (fitPoints.length < degree + 1) { throw new Error("At least ".concat(degree + 1, " points are required for a degree ").concat(degree, " closed spline")); } // Create spline using the constructor with fit points, degree, and closed=true return new AcGeSpline3d(fitPoints, parameterization, degree, true); }; return AcGeSpline3d; }(AcGeCurve3d)); export { AcGeSpline3d }; //# sourceMappingURL=AcGeSpline3d.js.map