jsketcher/modules/geom/surfaces/brepSurface.ts
2022-08-15 23:47:20 -07:00

201 lines
4.7 KiB
TypeScript

import {Point} from '../point';
import Vector, {UnitVector} from 'math/vector';
import {Plane} from '../impl/plane';
import BrepCurve from '../curves/brepCurve';
import {intersectNurbs} from './nurbsSurface';
import {IsoCurveU, IsoCurveV} from '../curves/IsoCurve';
import {ParametricSurface, UV} from "./parametricSurface";
import {Matrix3x4} from "math/matrix";
export class BrepSurface {
impl: ParametricSurface;
inverted: boolean;
private _simpleSurface: Plane;
private _mirrored: boolean;
uMin: number;
uMax: number;
vMin: number;
vMax: number;
uMid: number;
vMid: number;
constructor(surface: ParametricSurface, inverted?: boolean) {
this.impl = surface;
const [uMin, uMax] = surface.domainU;
const [vMin, vMax] = surface.domainV;
Object.assign(this, {
uMin, uMax, vMin, vMax,
uMid: (uMax - uMin) * 0.5,
vMid: (vMax - vMin) * 0.5
});
this.inverted = inverted === true;
}
get simpleSurface() {
return this._simpleSurface || (this._simpleSurface = figureOutSimpleSurface(this));
}
get mirrored() {
return this._mirrored || (this._mirrored = BrepSurface.isMirrored(this));
}
normal(point: Vector): Vector {
const uv = this.impl.param(point.data());
const normal = pt(this.impl.normal(uv[0], uv[1]));
if (this.inverted) {
normal._negate();
}
normal._normalize();
return normal;
}
normalUV(u: number, v: number): UnitVector {
const normal = pt(this.impl.normal(u, v));
if (this.inverted) {
normal._negate();
}
return normal._normalize();
}
normalInMiddle(): Vector {
return this.normalUV(this.uMid, this.vMid);
}
pointInMiddle(): Vector {
return this.point(this.uMid, this.vMid);
}
southWestPoint(): Vector {
return this.point(this.uMin, this.vMin);
}
southEastPoint(): Vector {
return this.point(this.uMax, this.vMin);
}
northEastPoint(): Vector {
return this.point(this.uMax, this.vMax);
}
northWestPoint(): Vector {
return this.point(this.uMin, this.vMax);
}
param(point) {
return this.impl.param(point.data());
}
point(u: number, v: number): Vector {
return pt(this.impl.point(u, v));
}
workingPoint(point: Vector): Vector {
return this.createWorkingPoint(this.impl.param(point.data()), point);
}
createWorkingPoint(uv: UV, pt3d: Vector): Vector {
const wp = new Vector(uv[0], uv[1], 0)._multiply(BrepSurface.WORKING_POINT_SCALE_FACTOR);
if (this.mirrored) {
wp.x *= -1;
}
wp.__3D = pt3d;
return wp;
}
workingPointTo3D(wp: Vector): Vector {
if (wp.__3D === undefined) {
const uv = wp.multiply(BrepSurface.WORKING_POINT_UNSCALE_FACTOR);
if (this.mirrored) {
uv.x *= -1;
}
wp.__3D = this.point(uv.x, uv.y);
}
return wp.__3D;
}
static isMirrored(surface) {
if (surface.impl.isMirrored !== undefined) {
return surface.impl.isMirrored;
}
const x = surface.isoCurveAlignU(surface.uMin).tangentAtParam(surface.uMin);
const y = surface.isoCurveAlignV(surface.vMin).tangentAtParam(surface.vMin);
return x.cross(y).dot(surface.normalUV(surface.uMin, surface.vMin)) < 0;
}
intersectSurface(other, tol) {
const X = intersectNurbs(this.impl, other.impl, this.inverted !== other.inverted);
// let X = surfaceIntersect(this.impl, other.impl);
return X.map(curve => new BrepCurve(curve));
}
invert() {
return new BrepSurface(this.impl, !this.inverted);
}
isoCurve(param, useV) {
let isoCurve;
// @ts-ignore
if (this.impl.isoCurve) {
// @ts-ignore
isoCurve = this.impl.isoCurve(param, useV);
} else {
isoCurve = useV ? new IsoCurveV(this.impl, param) : new IsoCurveU(this.impl, param);
}
return new BrepCurve(isoCurve);
}
isoCurveAlignU(param) {
return this.isoCurve(param, true);
}
isoCurveAlignV(param) {
return this.isoCurve(param, false);
}
tangentPlane(u, v) {
const normal = this.normalUV(u, v);
return new Plane(normal, normal.dot(this.point(u, v)));
}
tangentPlaneInMiddle() {
return this.tangentPlane(this.uMid, this.vMid);
}
transform(tr: Matrix3x4): BrepSurface {
const trArr = tr.toArray();
// trArr.push([0, 0, 0, 1]);
return new BrepSurface(this.impl.transform(trArr), this.inverted);
}
static WORKING_POINT_SCALE_FACTOR = 1000;
static WORKING_POINT_UNSCALE_FACTOR = 1 / BrepSurface.WORKING_POINT_SCALE_FACTOR;
}
function pt(data) {
return new Point().set3(data);
}
function figureOutSimpleSurface(srf) {
if (Math.max(srf.impl.degreeU(), srf.impl.degreeV()) === 1) {
return srf.tangentPlane(srf.uMid, srf.vMid);
}
return null;
}
declare module 'math/vector' {
export default interface Vector {
__3D: Vector;
}
}