From e01621bf67a64207ece2142a8665c4df01f98b55 Mon Sep 17 00:00:00 2001 From: "Val Erastov (xibyte)" Date: Mon, 5 Oct 2020 01:27:26 -0700 Subject: [PATCH] BREP serialization from Shell --- modules/brep/io/brepIO.ts | 162 ++++++++++++++------------ modules/engine/data/brepInputData.ts | 26 +++-- modules/engine/data/brepOutputData.ts | 4 +- modules/engine/data/curveData.ts | 7 +- modules/engine/data/surfaceData.ts | 21 ++-- modules/geom/curves/brepCurve.ts | 2 +- modules/geom/curves/nurbsCurve.ts | 11 ++ modules/geom/surfaces/nurbsSurface.ts | 12 ++ web/app/cad/debugPlugin.js | 36 +++++- web/app/cad/model/mshell.ts | 6 +- web/app/cad/sandbox.ts | 62 +++++++++- 11 files changed, 245 insertions(+), 104 deletions(-) diff --git a/modules/brep/io/brepIO.ts b/modules/brep/io/brepIO.ts index 64b2132e..44ca17a4 100644 --- a/modules/brep/io/brepIO.ts +++ b/modules/brep/io/brepIO.ts @@ -10,10 +10,14 @@ 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, EdgeData, FaceData} from "engine/data/brepOutputData"; +import {BrepOutputData} from "engine/data/brepOutputData"; import {ProductionInfo} from "engine/productionInfo"; import {Tessellation1D} from "engine/tessellation"; 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' { @@ -63,6 +67,7 @@ export function readBrep(data: BrepOutputData) { for (let faceData of data.faces) { bb.face(); + // @ts-ignore let nonDirect = faceData.surface.direct === false; // left handed coordinate system for planes let inverted = faceData.inverted !== nonDirect; bb._face.data.tessellation = { @@ -143,81 +148,86 @@ function readCurve(curve) { } -// export function writeBrep(shell: Shell): BrepOutputData { -// -// const brepData: BrepOutputData = { -// faces: [] -// }; -// -// for (let f of shell.faces) { -// const faceData: FaceData = { -// surface: writeSurface(f.surface), -// inverted: f.surface.inverted, -// loops: [] -// }; -// -// brepData.faces.push(faceData); -// -// for (let l of f.loops) { -// const loop = []; -// faceData.loops.push(loop); -// -// -// -// for (let he of l.halfEdges) { -// const vs = [he.vertexA, he.vertexB]; -// if (he.inverted) { -// vs.reverse(); -// } -// const [a, b] = vs; -// const curve = he.edge.curve; -// const edgeData: EdgeData = { -// a: a.point.toArray(), -// b: b.point.toArray(), -// -// inverted: he.inverted, -// curveBounds: curve.domain, -// -// curve: writeCurve(curve) -// -// }; -// loop.push(edgeData); -// } -// -// } -// } -// return brepData; -// } -// -// -// function writeSurface(surface: BrepSurface) { -// const impl = surface.impl; -// if (impl instanceof NurbsSurface) { -// const { -// degreeU, -// degreeV, -// controlPoints, -// knotsU, -// knotsV, -// weights -// } = impl.data; -// return { -// -// TYPE: "B-SPLINE", -// -// direct: surface.mirrored, -// -// degU: degreeU, -// degV: degreeV, -// knotsU: number[], -// knotsV: number[], -// weights: number[][], -// cp: controlPoints -// } -// } else { -// throw 'only nurbs'; -// } -// } +export function writeBrep(shell: Shell): BrepInputData { + + const brepData: BrepInputData = { + vertices: {}, + curves: {}, + surfaces: {}, + edges: {}, + faces: [] + }; + + const surfaces = new Map(); + const curves = new Map(); + const verts = new Map(); + const edges = new Map(); + + let vid = 0; + for (let v of shell.vertices) { + const id = 'v' + (vid++); + brepData.vertices[id] = v.point.data(); + verts.set(v, id); + } + + let cid = 0; + for (let e of shell.edges) { + e.curve.impl.asCurveBSplineData() + let curveId = curves.get(e.curve); + if (!curveId) { + curveId = 'c' + (cid++); + brepData.curves[curveId] = e.curve.impl.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 (let face of shell.faces) { + + let surfaceId = surfaces.get(face.surface.impl); + if (!surfaceId) { + surfaceId = 's' + (sid++); + + 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); + } + } + + + for (let face of shell.faces) { + const loops = []; + for (let loop of face.loops) { + 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) { let tess = []; diff --git a/modules/engine/data/brepInputData.ts b/modules/engine/data/brepInputData.ts index cc3f22a9..4b7994ae 100644 --- a/modules/engine/data/brepInputData.ts +++ b/modules/engine/data/brepInputData.ts @@ -1,7 +1,19 @@ import {SurfaceData} from "./surfaceData"; import {CurveData} from "./curveData"; import {Vec3} from "math/vec"; +import {SurfaceType} from "engine/data/brepOutputData"; +export interface BrepInputFaceData { + surface?: string; + loops: string[][]; + inverted?: boolean; +} + +export interface BrepInputEdgeData { + a: string; + b: string; + curve?: string; +} export interface BrepInputData { @@ -14,22 +26,14 @@ export interface BrepInputData { }, surfaces?: { - [id: string]: SurfaceData; + [id: string]: SurfaceType; }; edges: { - [id: string]: { - a: string; - b: string; - curve?: string; - inverted?: boolean; - }; + [id: string]: BrepInputEdgeData; }; - faces: { - surface?: string; - loops: string[][]; - }[]; + faces: BrepInputFaceData[]; } diff --git a/modules/engine/data/brepOutputData.ts b/modules/engine/data/brepOutputData.ts index 55eed845..4e6e2bcc 100644 --- a/modules/engine/data/brepOutputData.ts +++ b/modules/engine/data/brepOutputData.ts @@ -15,13 +15,15 @@ export interface BrepOutputData { } +export type SurfaceType = SurfacePlaneData | SurfaceBSplineData | SurfaceUnknownData; + export interface FaceData { ref: number; ptr: Handle; - surface: SurfacePlaneData | SurfaceBSplineData | SurfaceUnknownData; + surface: SurfaceType; inverted: boolean; tess?: Tessellation2D; productionInfo: ProductionInfo; diff --git a/modules/engine/data/curveData.ts b/modules/engine/data/curveData.ts index 8d1bce6c..0d85beaf 100644 --- a/modules/engine/data/curveData.ts +++ b/modules/engine/data/curveData.ts @@ -9,7 +9,12 @@ export interface CurveData { export interface CurveBSplineData extends CurveData { TYPE: "B-SPLINE"; - deg: number; + + degree?: number; + + //backward compat + deg?: number; + knots: number[]; weights: number[]; cp: Vec3[]; diff --git a/modules/engine/data/surfaceData.ts b/modules/engine/data/surfaceData.ts index 6bf5a15d..4f39f73b 100644 --- a/modules/engine/data/surfaceData.ts +++ b/modules/engine/data/surfaceData.ts @@ -3,9 +3,6 @@ import {Vec3} from "math/vec"; export interface SurfaceData { TYPE: string; - - direct: boolean; - } export interface SurfacePlaneData extends SurfaceData { @@ -16,17 +13,23 @@ export interface SurfacePlaneData extends SurfaceData { origin: Vec3; + direct?: boolean; } export interface SurfaceBSplineData extends SurfaceData { - TYPE: "B-SPLINE", + TYPE: "B-SPLINE" - degU: number - degV: number - knotsU: number[], - knotsV: number[], - weights: number[][], + degreeU?: number + degreeV?: number + + //backward compat + degU?: number + degV?: number + + knotsU: number[] + knotsV: number[] + weights: number[][] cp: Vec3[][] } diff --git a/modules/geom/curves/brepCurve.ts b/modules/geom/curves/brepCurve.ts index 73f73bc3..351bd934 100644 --- a/modules/geom/curves/brepCurve.ts +++ b/modules/geom/curves/brepCurve.ts @@ -13,7 +13,7 @@ import {Vec3} from "math/vec"; export default class BrepCurve { - impl: any; + impl: NurbsCurve; uMin: number; uMax: number; diff --git a/modules/geom/curves/nurbsCurve.ts b/modules/geom/curves/nurbsCurve.ts index 9c662e19..9cb6e10c 100644 --- a/modules/geom/curves/nurbsCurve.ts +++ b/modules/geom/curves/nurbsCurve.ts @@ -4,6 +4,7 @@ import {ParametricCurve} from "./parametricCurve"; import {Matrix3x4Data} from "math/matrix"; import {Vec3} from "math/vec"; import {NurbsCurveData} from "geom/curves/nurbsCurveData"; +import {CurveBSplineData} from "engine/data/curveData"; //in fact the sketcher format @@ -98,4 +99,14 @@ export default class NurbsCurve implements ParametricCurve { weights: this.verb.weights() } } + + asCurveBSplineData(): CurveBSplineData { + return { + TYPE: "B-SPLINE", + degree: this.verb.degree(), + knots: this.verb.knots(), + cp: this.verb.controlPoints(), + weights: this.verb.weights() + } + } } diff --git a/modules/geom/surfaces/nurbsSurface.ts b/modules/geom/surfaces/nurbsSurface.ts index 425b672c..4631d6bb 100644 --- a/modules/geom/surfaces/nurbsSurface.ts +++ b/modules/geom/surfaces/nurbsSurface.ts @@ -7,6 +7,7 @@ import {ParametricCurve} from "../curves/parametricCurve"; import {Matrix3x4Data} from "math/matrix"; import {Vec3} from "math/vec"; import {NurbsSurfaceData} from "geom/surfaces/nurbsSurfaceData"; +import {SurfaceBSplineData} from "engine/data/surfaceData"; export default class NurbsSurface implements ParametricSurface { @@ -84,6 +85,17 @@ export default class NurbsSurface implements ParametricSurface { throw 'unimplemented'; } + asSurfaceBSplineData(): SurfaceBSplineData { + return { + TYPE: "B-SPLINE", + degreeU: this.verb.degreeU(), + degreeV: this.verb.degreeV(), + knotsU: this.verb.knotsU(), + knotsV: this.verb.knotsV(), + weights: this.verb.weights(), + cp: this.verb.controlPoints() + } + } } const surTess = verb.eval.Tess.rationalSurfaceAdaptive; diff --git a/web/app/cad/debugPlugin.js b/web/app/cad/debugPlugin.js index 349a3560..9db718b5 100644 --- a/web/app/cad/debugPlugin.js +++ b/web/app/cad/debugPlugin.js @@ -10,6 +10,7 @@ import {toLoops} from 'brep/io/brepLoopsFormat'; import curveTess from 'geom/impl/curve/curve-tess'; import {LOG_FLAGS} from './logFlags'; import {state} from "lstream"; +import {BufferGeometry, BufferAttribute, Float32BufferAttribute, Int32BufferAttribute} from 'three'; const BREP_DEBUG_WINDOW_VISIBLE$ = state(false); @@ -194,7 +195,7 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) { for (let i = 0; i < triangles.length; ++i) { let off = geometry.vertices.length; let tr = triangles[i], normales; - if (Array.isArray(tr)) { + if (Array.isArray(tr[0][0])) { normales = tr[1]; tr = tr[0]; if (normales.find(n => n[0] === null || n[1] === null || n[2] === null)) { @@ -215,6 +216,39 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) { debugVolumeGroup.add(mesh); viewer.render(); }, + AddFacesTessellation: (faces) => { + const dump = []; + faces.forEach(face => { + + for (let i = 0; i < face.indices.length; i += 3) { + + const a = (face.indices[i + 0] - 1) * 3; + const b = (face.indices[i + 1] - 1) * 3; + const c = (face.indices[i + 2] - 1) * 3; + + dump.push([ + [ + face.positions[a + 0], + face.positions[a + 1], + face.positions[a + 2] + ], + [ + face.positions[b + 0], + face.positions[b + 1], + face.positions[b + 2] + ], + [ + face.positions[c + 0], + face.positions[c + 1], + face.positions[c + 2] + ], + ]); + } + + }) + __DEBUG__.AddTessDump(dump); + viewer.render(); + }, HideSolids: () => { cadRegistry.getAllShells().forEach(s => s.ext.view.mesh.traverse(o => o.visible = false)); viewer.render(); diff --git a/web/app/cad/model/mshell.ts b/web/app/cad/model/mshell.ts index 66c77f98..63318aaa 100644 --- a/web/app/cad/model/mshell.ts +++ b/web/app/cad/model/mshell.ts @@ -5,6 +5,8 @@ import {MVertex} from './mvertex'; import CSys from 'math/csys'; import {state, StateStream} from "lstream"; import {Matrix3x4} from "math/matrix"; +import {Shell} from "brep/topo/shell"; +import {TopoObject} from "brep/topo/topo-object"; export class MShell extends MObject { @@ -41,9 +43,9 @@ export class MShell extends MObject { export class MBrepShell extends MShell { - brepShell: any; + brepShell: Shell; csys: CSys; - brepRegistry: Map; + brepRegistry: Map; constructor(shell, csys) { super(); diff --git a/web/app/cad/sandbox.ts b/web/app/cad/sandbox.ts index 4bb338b5..aa075470 100644 --- a/web/app/cad/sandbox.ts +++ b/web/app/cad/sandbox.ts @@ -12,6 +12,9 @@ import {Vec3} from "math/vec"; import {ApplicationContext} from "context"; import {readShellEntityFromJson} from "./scene/wrappers/entityIO"; import {DEG_RAD} from "math/commons"; +import {DEFLECTION, E0_TOLERANCE} from "./craft/e0/common"; +import {readBrep, writeBrep} from "brep/io/brepIO"; +import {PRIMITIVE_TYPES} from "engine/data/primitiveData"; export function runSandbox(ctx: ApplicationContext) { @@ -325,10 +328,65 @@ export function runSandbox(ctx: ApplicationContext) { const mBrepShell = readShellEntityFromJson(data); - services.exposure.addOnScene(mBrepShell); + const serialized = writeBrep(mBrepShell.brepShell); + console.log(serialized); + let fromSerialization = ctx.craftEngine.modellingEngine.loadModel(serialized); + const mBrepShell2 = readShellEntityFromJson(data); + + services.exposure.addOnScene(mBrepShell2); } + function testTess() { + + let direction = [0, 0, 100]; + + let sketch = [[ + { + TYPE: PRIMITIVE_TYPES.SEGMENT, + a: [0, 0, 0], + b: [100, 0, 0], + }, + { + TYPE: PRIMITIVE_TYPES.SEGMENT, + a: [100, 0, 0], + b: [100, 100, 0], + }, + { + TYPE: PRIMITIVE_TYPES.SEGMENT, + a: [100, 100, 0], + b: [0, 100, 0], + }, + { + TYPE: PRIMITIVE_TYPES.SEGMENT, + a: [0, 100, 0], + b: [0, 0, 0], + }, + ]] + + let data = ctx.craftEngine.modellingEngine.extrude({ + vector: direction, + sketch: sketch, + tolerance: E0_TOLERANCE, + deflection: DEFLECTION + }) + + let brep = readBrep(data); + let tess = ctx.craftEngine.modellingEngine.tessellate({ + model: data.ptr, + deflection: DEFLECTION + }) + + __DEBUG__.AddFacesTessellation(tess.faces) + + console.dir(tess.faces) + + // const mBrepShell = readShellEntityFromJson(data); + + // services.exposure.addOnScene(mBrepShell); + + + } // cylinderAndPlaneIntersect(); // curvesIntersect(); @@ -347,7 +405,7 @@ export function runSandbox(ctx: ApplicationContext) { // window.voxelTest = voxelTest; ctx.streams.lifecycle.projectLoaded.attach(ready => { if (ready) { - testLoadBrep() + testLoadBrep(); } });