mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 16:33:15 +01:00
296 lines
7.9 KiB
TypeScript
296 lines
7.9 KiB
TypeScript
import BrepBuilder, {createBoundingSurfaceFromBBox} from '../brep-builder';
|
|
import VertexFactory from '../vertexFactory';
|
|
import NurbsSurface from 'geom/surfaces/nurbsSurface';
|
|
import * as vec from 'math/vec';
|
|
import {BrepSurface} from 'geom/surfaces/brepSurface';
|
|
import {Plane} from 'geom/impl/plane';
|
|
import Vector from 'math/vector';
|
|
import NullSurface from 'geom/surfaces/nullSurface';
|
|
import BBox from 'math/bbox';
|
|
import NurbsCurve from 'geom/curves/nurbsCurve';
|
|
import BrepCurve from 'geom/curves/brepCurve';
|
|
import {BrepOutputData} from "engine/data/brepOutputData";
|
|
import {Shell} from "brep/topo/shell";
|
|
import {BrepInputData} from "engine/data/brepInputData";
|
|
import {Vertex} from "brep/topo/vertex";
|
|
import {Edge} from "brep/topo/edge";
|
|
import {ParametricSurface} from "geom/surfaces/parametricSurface";
|
|
|
|
//Extensions for topo objects
|
|
// declare module '../topo/shell' {
|
|
//
|
|
// interface Shell {
|
|
// data: {
|
|
// externals: {
|
|
// ptr?: number
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// declare module '../topo/face' {
|
|
//
|
|
// interface Face {
|
|
// data: {
|
|
// id: string,
|
|
// productionInfo: ProductionInfo,
|
|
// tessellation: {
|
|
// format: string,
|
|
// data: any;
|
|
// }
|
|
// externals: {
|
|
// ref: number,
|
|
// ptr: number
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// declare module '../topo/edge' {
|
|
//
|
|
// interface Edge {
|
|
// data: {
|
|
// tessellation: Tessellation1D<Vec3>
|
|
// externals: {
|
|
// ptr?: number
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
export function readBrep(data: BrepOutputData) {
|
|
|
|
const bb = new BrepBuilder();
|
|
const vf = new VertexFactory();
|
|
|
|
for (const faceData of data.faces) {
|
|
bb.face();
|
|
// @ts-ignore
|
|
const nonDirect = faceData.surface.direct === false; // left handed coordinate system for planes
|
|
const inverted = faceData.inverted !== nonDirect;
|
|
bb._face.data.tessellation = {
|
|
format: 'verbose',
|
|
data: normalizetessellationData(faceData.tess, inverted, faceData.surface.TYPE === 'PLANE' ? faceData.surface.normal : undefined)
|
|
};
|
|
bb._face.data.productionInfo = faceData.productionInfo;
|
|
if (faceData.ref !== undefined) {
|
|
bb._face.data.externals = {
|
|
ref: faceData.ref,
|
|
ptr: faceData.ptr,
|
|
}
|
|
}
|
|
|
|
for (const loop of faceData.loops) {
|
|
bb.loop();
|
|
for (const edgeData of loop) {
|
|
const a = vf.getData(edgeData.inverted ? edgeData.b : edgeData.a);
|
|
const b = vf.getData(edgeData.inverted ? edgeData.a : edgeData.b);
|
|
bb.edge(a, b, () => readCurve(edgeData.curve), edgeData.inverted, edgeData.edgeRef);
|
|
bb.lastHalfEdge.edge.data.tessellation = edgeData.tess;
|
|
//todo: data should provide full externals object
|
|
bb.lastHalfEdge.edge.data.externals = {
|
|
ptr: edgeData.ptr
|
|
};
|
|
}
|
|
}
|
|
try {
|
|
bb._face.surface = readSurface(faceData.surface, faceData.inverted, inverted, bb._face);
|
|
} catch (e) {
|
|
console.error(e);
|
|
bb._face.surface = new BrepSurface(new NullSurface());
|
|
}
|
|
}
|
|
//todo: data should provide full externals object
|
|
bb._shell.data.externals = {
|
|
ptr: data.ptr
|
|
};
|
|
return bb.build();
|
|
}
|
|
|
|
function readSurface(s, faceInverted, effectivelyInverted, face) {
|
|
let surface;
|
|
if (s.TYPE === 'B-SPLINE') {
|
|
surface = new BrepSurface(NurbsSurface.create(s.degU, s.degV, s.knotsU, s.knotsV, s.cp, s.weights), faceInverted);
|
|
surface._mirrored = !s.direct;
|
|
} else if (s.TYPE === 'PLANE') {
|
|
|
|
const normal = new Vector().set3(s.normal).asUnitVector();
|
|
let plane = new Plane(normal, normal.dot(new Vector().set3(s.origin)));
|
|
if (effectivelyInverted) {
|
|
plane = plane.invert();
|
|
}
|
|
const bBox = new BBox();
|
|
|
|
const tr = plane.get2DTransformation();
|
|
for (const he of face.outerLoop.halfEdges) {
|
|
const tess = he.edge.data.tessellation ? he.edge.data.tessellation : he.edge.curve.tessellateToData();
|
|
tess.forEach(p => bBox.checkData(tr.apply3(p)));
|
|
}
|
|
bBox.expand(10);
|
|
surface = createBoundingSurfaceFromBBox(bBox, plane);
|
|
} else {
|
|
surface = new BrepSurface(new NullSurface());
|
|
}
|
|
return surface;
|
|
}
|
|
|
|
function readCurve(curve) {
|
|
switch (curve.TYPE) {
|
|
case 'B-SPLINE':
|
|
return new BrepCurve(NurbsCurve.create(curve.deg, curve.knots, curve.cp, curve.weights));
|
|
case 'CONIC':
|
|
//...
|
|
case 'LINE':
|
|
default:
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
|
|
export function writeBrep(shell: Shell): BrepInputData {
|
|
|
|
const brepData: BrepInputData = {
|
|
vertices: {},
|
|
curves: {},
|
|
surfaces: {},
|
|
edges: {},
|
|
faces: []
|
|
};
|
|
|
|
const surfaces = new Map<ParametricSurface, string>();
|
|
const curves = new Map<BrepCurve, string>();
|
|
const verts = new Map<Vertex, string>();
|
|
const edges = new Map<Edge, string>();
|
|
|
|
let vid = 0;
|
|
for (const v of shell.vertices) {
|
|
const id = 'v' + (vid++);
|
|
brepData.vertices[id] = v.point.data();
|
|
verts.set(v, id);
|
|
}
|
|
|
|
let cid = 0;
|
|
for (const e of shell.edges) {
|
|
let curveId = curves.get(e.curve);
|
|
// since we it can't be non smooth splines without a vertex - simple just skip it
|
|
if (!curveId && e.curve.degree != 1) {
|
|
curveId = 'c' + (cid++);
|
|
brepData.curves[curveId] = (e.curve.impl as NurbsCurve).asCurveBSplineData();
|
|
curves.set(e.curve, curveId);
|
|
}
|
|
|
|
const a = verts.get(e.halfEdge1.vertexA);
|
|
const b = verts.get(e.halfEdge1.vertexB);
|
|
const edgeId = a + '_' + b;
|
|
|
|
brepData.edges[edgeId] = {
|
|
a, b,
|
|
curve: curveId
|
|
}
|
|
|
|
edges.set(e, edgeId);
|
|
|
|
}
|
|
|
|
let sid = 0;
|
|
for (const face of shell.faces) {
|
|
|
|
let surfaceId = surfaces.get(face.surface.impl);
|
|
if (!surfaceId) {
|
|
surfaceId = 's' + (sid++);
|
|
const plane = face.surface.simpleSurface as Plane;
|
|
if (plane !== null) {
|
|
brepData.surfaces[surfaceId] = {
|
|
TYPE: 'PLANE',
|
|
normal: plane.normal.data(),
|
|
origin: plane.normal.multiply(plane.w).data()
|
|
}
|
|
} else {
|
|
brepData.surfaces[surfaceId] = {
|
|
... (face.surface.impl as NurbsSurface).asSurfaceBSplineData()
|
|
}
|
|
}
|
|
|
|
|
|
//direct needed only for planes
|
|
//direct: face.surface.mirrored ? false : undefined
|
|
|
|
surfaces.set(face.surface.impl, surfaceId);
|
|
}
|
|
}
|
|
|
|
|
|
FACES:
|
|
for (const face of shell.faces) {
|
|
const loops = [];
|
|
for (const loop of face.loops) {
|
|
if (loop.halfEdges.length == 0) {
|
|
continue FACES;
|
|
}
|
|
loops.push(loop.halfEdges.map(he => edges.get(he.edge)));
|
|
}
|
|
|
|
brepData.faces.push({
|
|
surface: surfaces.get(face.surface.impl),
|
|
inverted: face.surface.inverted,
|
|
loops
|
|
})
|
|
}
|
|
return brepData;
|
|
}
|
|
|
|
|
|
|
|
export function normalizetessellationData(tessellation, inverted, surfaceNormal) {
|
|
const tess = [];
|
|
for (let i = 0; i < tessellation.length; ++i) {
|
|
let [tr, normales] = tessellation[i];
|
|
tr = tr.slice();
|
|
if (normales) {
|
|
const normalesValid = !normales.find(n => n[0] === null || n[1] === null || n[2] === null);
|
|
if (!normalesValid) {
|
|
normales = undefined;
|
|
} else {
|
|
if (inverted) {
|
|
normales = normales.map(n => vec.negate(n));
|
|
} else {
|
|
normales = normales.slice();
|
|
}
|
|
}
|
|
}
|
|
if (inverted) {
|
|
tr.reverse();
|
|
if (normales) {
|
|
normales.reverse();
|
|
}
|
|
}
|
|
tess.push([tr, normales]);
|
|
}
|
|
if (surfaceNormal && inverted) {
|
|
surfaceNormal = vec.negate(surfaceNormal);
|
|
}
|
|
|
|
for (const [tr, normales] of tess) {
|
|
if (normales) {
|
|
const trNormal = vec.normal3(tr);
|
|
const testNormal = normalizedSum(normales);
|
|
if (vec.dot(testNormal, trNormal) < 0) {
|
|
tr.reverse();
|
|
normales.reverse();
|
|
}
|
|
} else if (surfaceNormal) {
|
|
const trNormal = vec.normal3(tr);
|
|
if (vec.dot(surfaceNormal, trNormal) < 0) {
|
|
tr.reverse();
|
|
}
|
|
}
|
|
}
|
|
return tess;
|
|
}
|
|
|
|
function normalizedSum(vecs) {
|
|
const out = [0,0,0];
|
|
vecs.forEach(v => vec._add(out, v));
|
|
vec._normalize(out);
|
|
return out;
|
|
}
|