@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
218 lines • 7.47 kB
JavaScript
/**
* NURBS utility functions for spline calculations
*/
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
/**
* Generate uniform knot vector
*/
export function generateUniformKnots(degree, numControlPoints) {
var knots = [];
var n = numControlPoints - 1;
var p = degree;
// First p+1 knots are 0
for (var i = 0; i <= p; i++) {
knots.push(0);
}
// Middle knots are uniform
for (var i = 1; i <= n - p; i++) {
knots.push(i);
}
// Last p+1 knots are n-p+1
for (var i = 0; i <= p; i++) {
knots.push(n - p + 1);
}
return knots;
}
/**
* Generate chord-length parameterized knots
*/
export function generateChordKnots(degree, points) {
var n = points.length - 1;
var p = degree;
// Calculate chord lengths
var chordLengths = [0];
var totalLength = 0;
for (var i = 1; i <= n; i++) {
var dx = points[i][0] - points[i - 1][0];
var dy = points[i][1] - points[i - 1][1];
var dz = points[i][2] - points[i - 1][2];
var length_1 = Math.sqrt(dx * dx + dy * dy + dz * dz);
totalLength += length_1;
chordLengths.push(totalLength);
}
// Generate knots based on chord lengths
var knots = [];
// First p+1 knots are 0
for (var i = 0; i <= p; i++) {
knots.push(0);
}
// Middle knots based on chord lengths
for (var i = 1; i <= n - p; i++) {
var t = chordLengths[i] / totalLength;
knots.push(t * (n - p + 1));
}
// Last p+1 knots are n-p+1
for (var i = 0; i <= p; i++) {
knots.push(n - p + 1);
}
return knots;
}
/**
* Generate sqrt-chord parameterized knots
*/
export function generateSqrtChordKnots(degree, points) {
var n = points.length - 1;
var p = degree;
// Calculate sqrt chord lengths
var sqrtChordLengths = [0];
var totalSqrtLength = 0;
for (var i = 1; i <= n; i++) {
var dx = points[i][0] - points[i - 1][0];
var dy = points[i][1] - points[i - 1][1];
var dz = points[i][2] - points[i - 1][2];
var length_2 = Math.sqrt(dx * dx + dy * dy + dz * dz);
var sqrtLength = Math.sqrt(length_2);
totalSqrtLength += sqrtLength;
sqrtChordLengths.push(totalSqrtLength);
}
// Generate knots based on sqrt chord lengths
var knots = [];
// First p+1 knots are 0
for (var i = 0; i <= p; i++) {
knots.push(0);
}
// Middle knots based on sqrt chord lengths
for (var i = 1; i <= n - p; i++) {
var t = sqrtChordLengths[i] / totalSqrtLength;
knots.push(t * (n - p + 1));
}
// Last p+1 knots are n-p+1
for (var i = 0; i <= p; i++) {
knots.push(n - p + 1);
}
return knots;
}
/**
* Calculate basis function value for NURBS
*/
export function basisFunction(i, k, u, knots) {
if (k === 0) {
return u >= knots[i] && u < knots[i + 1] ? 1.0 : 0.0;
}
var d1 = knots[i + k] - knots[i];
var d2 = knots[i + k + 1] - knots[i + 1];
var c1 = d1 > 1e-10 ? (u - knots[i]) / d1 : 0.0;
var c2 = d2 > 1e-10 ? (knots[i + k + 1] - u) / d2 : 0.0;
return (c1 * basisFunction(i, k - 1, u, knots) +
c2 * basisFunction(i + 1, k - 1, u, knots));
}
/**
* Calculate point on NURBS curve
*/
export function evaluateNurbsPoint(u, degree, knots, controlPoints, weights) {
var n = controlPoints.length - 1;
var p = degree;
// Clamp parameter to valid range
u = Math.max(knots[p], Math.min(knots[n + 1], u));
// If u is very close to the end, return the last control point
if (Math.abs(u - knots[n + 1]) < 1e-8) {
return __spreadArray([], __read(controlPoints[n]), false);
}
// If u is very close to the start, return the first control point
if (Math.abs(u - knots[p]) < 1e-8) {
return __spreadArray([], __read(controlPoints[0]), false);
}
var point = [0, 0, 0];
var weight = 0;
for (var i = 0; i <= n; i++) {
var basis = basisFunction(i, p, u, knots);
var w = weights[i] * basis;
point[0] += controlPoints[i][0] * w;
point[1] += controlPoints[i][1] * w;
point[2] += controlPoints[i][2] * w;
weight += w;
}
// If weight is very small (all basis functions are zero),
// check if we're at the end and return the last control point
if (weight < 1e-10) {
// Check if we're at the end of the domain
var endParam = knots[knots.length - p - 1];
if (Math.abs(u - endParam) < 1e-8) {
return __spreadArray([], __read(controlPoints[n]), false);
}
// Check if we're at the start of the domain
if (Math.abs(u - knots[p]) < 1e-8) {
return __spreadArray([], __read(controlPoints[0]), false);
}
}
if (weight > 1e-10) {
point[0] /= weight;
point[1] /= weight;
point[2] /= weight;
}
return point;
}
/**
* Calculate curve length using numerical integration
*/
export function calculateCurveLength(degree, knots, controlPoints, weights) {
var p = degree;
var startParam = knots[p];
var endParam = knots[knots.length - p - 1];
var length = 0;
var steps = 1000;
var step = (endParam - startParam) / steps;
var prevPoint = evaluateNurbsPoint(startParam, degree, knots, controlPoints, weights);
for (var i = 1; i <= steps; i++) {
var u = startParam + i * step;
var point = evaluateNurbsPoint(u, degree, knots, controlPoints, weights);
var dx_1 = point[0] - prevPoint[0];
var dy_1 = point[1] - prevPoint[1];
var dz_1 = point[2] - prevPoint[2];
length += Math.sqrt(dx_1 * dx_1 + dy_1 * dy_1 + dz_1 * dz_1);
prevPoint = point;
}
// Add the final segment to the end point
var finalPoint = evaluateNurbsPoint(endParam, degree, knots, controlPoints, weights);
var dx = finalPoint[0] - prevPoint[0];
var dy = finalPoint[1] - prevPoint[1];
var dz = finalPoint[2] - prevPoint[2];
length += Math.sqrt(dx * dx + dy * dy + dz * dz);
return length;
}
/**
* Generate control points from fit points using interpolation
* This is a simplified implementation - for production use, you might want
* to implement a more sophisticated interpolation algorithm
*/
export function interpolateControlPoints(fitPoints) {
// For now, use fit points as control points
// In a full implementation, you would solve the interpolation system
// by setting up and solving a linear system of equations
return fitPoints.map(function (p) { return __spreadArray([], __read(p), false); });
}
//# sourceMappingURL=AcGeNurbsUtil.js.map