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

218 lines 7.47 kB
/** * 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