jsketcher/web/app/brep/geom/impl/nurbs.js
2018-03-09 19:00:49 -08:00

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;
}