mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 17:04:58 +01:00
196 lines
No EOL
5.1 KiB
JavaScript
196 lines
No EOL
5.1 KiB
JavaScript
import {BasisForPlane, Matrix3} from '../../../math/l3space'
|
|
import * as math from '../../../math/math'
|
|
import {Point} from '../point'
|
|
import {Surface} from "../surface";
|
|
import Vector from 'math/vector';
|
|
import * as ext from "./nurbs-ext";
|
|
import {EPSILON, eqEps, eqSqTol, TOLERANCE, TOLERANCE_SQ, ueq, veq, veq3, veqNeg} from "../tolerance";
|
|
import curveIntersect from "./curve/curves-isec";
|
|
import curveTess from "./curve/curve-tess";
|
|
import {areEqual} from "../../../math/math";
|
|
import {Plane} from "./plane";
|
|
import BrepCurve from "../curves/brepCurve";
|
|
import NurbsCurve from "../curves/nurbsCurve";
|
|
import cache from "./cache";
|
|
|
|
export class NurbsSurface extends Surface {
|
|
|
|
constructor(verbSurface, inverted, simpleSurface) {
|
|
super();
|
|
let {min: uMin, max: uMax} = verbSurface.domainU();
|
|
let {min: vMin, max: vMax} = verbSurface.domainV();
|
|
|
|
if (uMin !== 0 || uMax !== 1 || vMin !== 0 || vMax !== 1) {
|
|
throw 'only normalized(0..1) parametrization is supported';
|
|
}
|
|
|
|
this.data = verbSurface.asNurbs();
|
|
this.verb = verbSurface;
|
|
this.inverted = inverted === true;
|
|
this.mirrored = NurbsSurface.isMirrored(this);
|
|
this.simpleSurface = simpleSurface || figureOutSimpleSurface(this);
|
|
}
|
|
|
|
domainU() {
|
|
return this.verb.domainU();
|
|
}
|
|
|
|
domainV() {
|
|
return this.verb.domainV();
|
|
}
|
|
|
|
middle() {
|
|
let {min: uMin, max: uMax} = this.verb.domainU();
|
|
let {min: vMin, max: vMax} = this.verb.domainV();
|
|
return [
|
|
(uMax - uMin) * 0.5,
|
|
(vMax - vMin) * 0.5
|
|
];
|
|
}
|
|
|
|
toNurbs() {
|
|
return this;
|
|
}
|
|
|
|
normal(point) {
|
|
let uv = this.verb.closestParam(point.data());
|
|
let normal = pt(this.verb.normal(uv[0], uv[1]));
|
|
if (this.inverted) {
|
|
normal._negate();
|
|
}
|
|
normal._normalize();
|
|
return normal;
|
|
}
|
|
|
|
normalUV(u, v) {
|
|
let normal = pt(this.verb.normal(u, v));
|
|
if (this.inverted) {
|
|
normal._negate();
|
|
}
|
|
normal._normalize();
|
|
return normal;
|
|
}
|
|
|
|
normalInMiddle() {
|
|
//TODO: use domain!
|
|
return this.normalUV(0.5, 0.5);
|
|
}
|
|
|
|
pointInMiddle() {
|
|
//TODO: use domain!
|
|
return this.point(0.5, 0.5);
|
|
}
|
|
|
|
|
|
param(point) {
|
|
return this.verb.closestParam(point.data());
|
|
}
|
|
|
|
point(u, v) {
|
|
return pt(this.verb.point(u, v));
|
|
}
|
|
|
|
workingPoint(point) {
|
|
return this.createWorkingPoint(this.verb.closestParam(point.data()), point);
|
|
}
|
|
|
|
createWorkingPoint(uv, pt3d) {
|
|
const wp = new Vector(uv[0], uv[1], 0)._multiply(NurbsSurface.WORKING_POINT_SCALE_FACTOR);
|
|
if (this.mirrored) {
|
|
wp.x *= -1;
|
|
}
|
|
wp.__3D = pt3d;
|
|
return wp;
|
|
}
|
|
|
|
workingPointTo3D(wp) {
|
|
if (wp.__3D === undefined) {
|
|
const uv = wp.multiply(NurbsSurface.WORKING_POINT_UNSCALE_FACTOR);
|
|
if (this.mirrored) {
|
|
uv.x *= -1;
|
|
}
|
|
wp.__3D = this.point(uv.x, uv.y);
|
|
}
|
|
return wp.__3D;
|
|
}
|
|
|
|
static isMirrored(surface) {
|
|
let {min: uMin} = surface.domainU();
|
|
let {min: vMin} = surface.domainV();
|
|
|
|
let x = surface.isoCurveAlignU(uMin).tangentAtParam(uMin);
|
|
let y = surface.isoCurveAlignV(vMin).tangentAtParam(vMin);
|
|
|
|
return x.cross(y).dot(surface.normalUV(uMin, vMin)) < 0;
|
|
}
|
|
|
|
intersectSurfaceForSameClass(other) {
|
|
let curves = ext.surfaceIntersect(this.data, other.data);
|
|
let inverted = this.inverted !== other.inverted;
|
|
if (inverted) {
|
|
curves = curves.map(curve => ext.curveInvert(curve));
|
|
}
|
|
curves.forEach(curve => ext.normalizeCurveParametrizationIfNeeded(curve))
|
|
return curves.map(curve => new BrepCurve(new NurbsCurve(newVerbCurve(curve))));
|
|
}
|
|
|
|
invert() {
|
|
return new NurbsSurface(this.verb, !this.inverted);
|
|
}
|
|
|
|
isoCurve(param, useV) {
|
|
const data = verb.eval.Make.surfaceIsocurve(this.verb._data, param, useV);
|
|
const isoCurve = newVerbCurve(data);
|
|
return new BrepCurve(new NurbsCurve(isoCurve));
|
|
}
|
|
|
|
isoCurveAlignU(param) {
|
|
return this.isoCurve(param, true);
|
|
}
|
|
|
|
isoCurveAlignV(param) {
|
|
return this.isoCurve(param, false);
|
|
}
|
|
|
|
intersectWithCurve(curve) {
|
|
return verb.geom.Intersect.curveAndSurface(curve.impl.verb, this.verb, TOLERANCE).map(({uv}) => uv);
|
|
}
|
|
|
|
tangentPlane(u, v) {
|
|
let normal = this.normalUV(u, v);
|
|
return new Plane(normal, normal.dot(this.point(u, v)));
|
|
}
|
|
|
|
tangentPlaneInMiddle() {
|
|
return this.tangentPlane(0.5, 0.5);
|
|
}
|
|
}
|
|
|
|
NurbsSurface.WORKING_POINT_SCALE_FACTOR = 1000;
|
|
NurbsSurface.WORKING_POINT_UNSCALE_FACTOR = 1 / NurbsSurface.WORKING_POINT_SCALE_FACTOR;
|
|
|
|
NurbsSurface.loft = function(curve1, curve2) {
|
|
return new NurbsSurface(verb.geom.NurbsSurface.byLoftingCurves([curve1.impl.verb, curve2.impl.verb], 1));
|
|
};
|
|
|
|
export function newVerbCurve(data) {
|
|
return new verb.geom.NurbsCurve(data);
|
|
}
|
|
|
|
function pt(data) {
|
|
return new Point().set3(data);
|
|
}
|
|
|
|
const surTess = verb.eval.Tess.rationalSurfaceAdaptive;
|
|
verb.eval.Tess.rationalSurfaceAdaptive = function(surface, opts) {
|
|
const keys = [opts ? opts.maxDepth: 'undefined'];
|
|
return cache('tess', keys, surface, () => surTess(surface, opts));
|
|
};
|
|
|
|
function figureOutSimpleSurface(nurbs) {
|
|
if (ext.surfaceMaxDegree(nurbs.data) === 1) {
|
|
//TODO: use domain!
|
|
return nurbs.tangentPlane(0.5, 0.5);
|
|
}
|
|
return null;
|
|
} |