@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
JavaScript
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