engine API grooming

This commit is contained in:
Val Erastov (xibyte) 2020-07-21 00:54:09 -07:00
parent 3090e62cee
commit da4631458b
14 changed files with 361 additions and 291 deletions

View file

@ -15,7 +15,20 @@ export interface OperationError {
message?: string;
}
export type BREPResponse = BREPData | OperationError
export type GenericResponse = OperationError | {
/**
* List of consumed objects
*/
consumed: Handle[];
/**
* List of create by the boolean operation objects
*/
created: BREPData[];
}
export type SingleResponse = OperationError | BREPData;
export interface EngineAPI_V1 {
@ -49,7 +62,7 @@ export interface EngineAPI_V1 {
*/
boolean: UnaryBooleanOptions;
}): BREPResponse;
}): SingleResponse;
/**
@ -92,7 +105,7 @@ export interface EngineAPI_V1 {
*/
boolean: UnaryBooleanOptions;
}): BREPResponse;
}): SingleResponse;
/**
@ -116,7 +129,7 @@ export interface EngineAPI_V1 {
deflection: number;
}): BREPResponse;
}): GenericResponse;
/**
@ -164,14 +177,14 @@ export interface EngineAPI_V1 {
* thickness of the fillet from one edge to another
*/
thickness: number;
}
}[]
/**
* Tessellation detail parameter
*/
deflection: number;
}): BREPResponse;
}): SingleResponse;
/**
* Generic boolean operation on given operands
@ -194,7 +207,9 @@ export interface EngineAPI_V1 {
*/
deflection: number;
}): BREPResponse;
}): OperationError | {
result: BREPData
};
/**
@ -228,7 +243,7 @@ export interface EngineAPI_V1 {
boolean: BooleanOptions
}): BREPResponse;
}): GenericResponse;
/**
@ -251,7 +266,7 @@ export interface EngineAPI_V1 {
*/
boolean: BooleanOptions
}): BREPResponse;
}): GenericResponse;
/**
@ -284,7 +299,7 @@ export interface EngineAPI_V1 {
*/
boolean: BooleanOptions
}): BREPResponse;
}): GenericResponse;
/**
* Creates a cylinder
@ -311,7 +326,7 @@ export interface EngineAPI_V1 {
*/
boolean: BooleanOptions
}): BREPResponse;
}): GenericResponse;
/**
* Creates a torus
@ -338,7 +353,7 @@ export interface EngineAPI_V1 {
*/
boolean: BooleanOptions
}): BREPResponse;
}): GenericResponse;
/**
* Imports a step file by its 'file reference'. The usage of this API is implementation specific. In webassembly environments
@ -352,7 +367,7 @@ export interface EngineAPI_V1 {
*/
file: string
}): BREPResponse;
}): GenericResponse;
}

View file

@ -0,0 +1,56 @@
import {EngineAPI_V1} from "engine/api";
import {Vec3} from "math/vec";
import {Tessellation2D} from "engine/tessellation";
import {callEngine} from "engine/impl/wasm/interact";
export class GenericWASMEngine_V1 implements EngineAPI_V1 {
boolean(params) {
return callEngine(params, Module._SPI_boolean);
}
createBox(params) {
return callEngine(params, Module._SPI_box);
}
createCone(params) {
return callEngine(params, Module._SPI_cone);
}
createCylinder(params) {
return callEngine(params, Module._SPI_cylinder);
}
createSphere(params) {
return callEngine(params, Module._SPI_sphere);
}
createTorus(params) {
return callEngine(params, Module._SPI_torus);
}
extrude(params) {
return callEngine(params, Module._SPI_extrude);
}
fillet(params) {
return callEngine(params, Module._SPI_fillet);
}
loft(params) {
return callEngine(params, Module._SPI_loft);
}
loftPreview(params): Tessellation2D<Vec3> {
return callEngine(params, Module._SPI_loftPreview) as Tessellation2D<Vec3>;
}
revolve(params) {
return callEngine(params, Module._SPI_revolve);
}
stepImport(params) {
return callEngine(params, Module._SPI_stepImport);
}
}

15
modules/engine/impl/wasm/externals.d.ts vendored Normal file
View file

@ -0,0 +1,15 @@
declare var Module: {
_SPI_box: Function;
_SPI_torus: Function;
_SPI_sphere: Function;
_SPI_cylinder: Function;
_SPI_cone: Function;
_SPI_boolean: Function,
_SPI_extrude: Function;
_SPI_stepImport: Function;
_SPI_revolve: Function;
_SPI_loftPreview: Function;
_SPI_loft: Function;
_SPI_fillet: Function;
};

View file

@ -2,6 +2,11 @@ import {MShell} from '../model/mshell';
import {MObject} from "../model/mobject";
import {ApplicationContext} from "context";
import {Stream} from "lstream";
import {MFace} from "../model/mface";
import {MEdge} from "../model/medge";
import {MSketchObject} from "../model/msketchObject";
import {MDatum, MDatumAxis} from "../model/mdatum";
import {MLoop} from "../model/mloop";
export function activate(ctx: ApplicationContext) {
@ -81,15 +86,14 @@ export function activate(ctx: ApplicationContext) {
export interface CadRegistry {
getAllShells(): MShell[];
findShell(id: string): MObject;
findFace(id: string): MObject;
findEdge(id: string): MObject;
findSketchObject(id: string): MObject;
findShell(id: string): MShell;
findFace(id: string): MFace;
findEdge(id: string): MEdge;
findSketchObject(id: string): MSketchObject;
findEntity(id: string): MObject;
findEntity(id: string): MObject;
findDatum(id: string): MObject;
findDatumAxis(id: string): MObject;
findLoop(id: string): MObject;
findDatum(id: string): MDatum;
findDatumAxis(id: string): MDatumAxis;
findLoop(id: string): MLoop;
find(id: string): MObject;
modelIndex: Map<String, MObject>;
models: MObject[];

View file

@ -5,11 +5,16 @@ import {equal} from 'math/equality';
export function Extrude(params, ctx) {
return doOperation(params, ctx, false);
// return doOperation(params, ctx, false);
return ctx.craftEngine.cutExtrude(false, params);
}
export function Cut(params, ctx) {
return doOperation(params, ctx, true);
// return doOperation(params, ctx, true);
return ctx.craftEngine.cutExtrude(true, params);
}
export function doOperation(params, ctx, cut) {

View file

@ -0,0 +1,231 @@
import {
DEFLECTION,
E0_TOLERANCE,
managedByE0,
readShellData, readSketch,
readSketchContour,
shellsToPointers, singleShellRespone,
writeCsys
} from './common';
import * as vec from 'math/vec';
import {MOpenFaceShell} from '../../model/mopenFace';
import {BooleanType, EngineAPI_V1} from "engine/api";
import {callEngine} from "engine/impl/wasm/interact";
import {resolveExtrudeVector} from "../cutExtrude/cutExtrude";
import {ApplicationContext} from "context";
import {MBrepShell} from "../../model/mshell";
/**
* Temporary dump of "bridging" functions between external engines and modeller world
*/
export class CraftEngine {
modellingEngine: EngineAPI_V1;
ctx: ApplicationContext;
constructor(modellingEngine: EngineAPI_V1, ctx: ApplicationContext) {
this.modellingEngine = modellingEngine;
this.ctx = ctx;
}
boolean({type, operandsA, operandsB}) {
let engineParams = {
type: <BooleanType>(BooleanType[type] as any),
operandsA: shellsToPointers(operandsA),
operandsB: shellsToPointers(operandsB),
tolerance: E0_TOLERANCE,
deflection: DEFLECTION,
};
let data = this.modellingEngine.boolean(engineParams) as any;
let consumed = [...operandsA, ...operandsB];
return {
consumed,
created: [readShellData(data.result, consumed, operandsA[0].csys)]
}
}
createBox(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
dx: params.width,
dy: params.height,
dz: params.depth
}, params, (params) => this.modellingEngine.createBox(params));
}
createTorus(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
r1: params.radius,
r2: params.tube
}, params, (params) => this.modellingEngine.createTorus(params));
}
createCone(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys, true),
r1: params.radius,
r2: params.frustum,
h: params.height
}, params, (params) => this.modellingEngine.createCone(params));
}
createCylinder(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys, true),
r: params.radius,
h: params.height,
}, params, (params) => this.modellingEngine.createCylinder(params));
}
createSphere(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
r: params.radius,
}, params, (params) => this.modellingEngine.createSphere(params));
}
stepImport(params) {
let shape = this.modellingEngine.stepImport({
file: params.file
});
return {
consumed: [], created: [readShellData(shape, [], undefined)]
}
}
cutExtrude(isCut, request) {
let {request: engineReq, face} = createExtrudeCommand(request, this.ctx, isCut);
if (managedByE0(face.shell)) {
// @ts-ignore
engineReq.boolean = {
type: isCut ? BooleanType.SUBTRACT : BooleanType.UNION,
operand: face.shell.brepShell.data.externals.ptr
}
}
let data = callEngine(engineReq, Module._SPI_extrude);
return singleShellRespone(face.shell, data);
}
revolve(request) {
let {request: engineReq, face} = createRevolveCommand(request, this.ctx);
let data = this.modellingEngine.revolve(engineReq as any);
return singleShellRespone(face.shell, data);
}
loftPreview(params) {
return this.modellingEngine.loftPreview(params);
}
loft(params) {
let data = this.modellingEngine.loft(mapLoftParams(params));
let baseShell = params.sections[0].face.shell;
let consumed = params.sections
.filter(s => (!(s.face.shell instanceof MOpenFaceShell) || s.face.sketchLoops.length === 1))
.map(s => s.face.shell);
return {
consumed,
created: [readShellData(data, consumed, baseShell.csys)]
}
}
fillet(request) {
let edge = this.ctx.cadRegistry.findEdge(request.edges[0]);
let engineReq = {
deflection: DEFLECTION,
solid: edge.shell.brepShell.data.externals.ptr,
edges: request.edges.map(e => ({
edge: this.ctx.cadRegistry.findEdge(e).brepEdge.data.externals.ptr,
thickness: request.thickness
}))
};
let data = this.modellingEngine.fillet(engineReq);
return singleShellRespone(edge.shell, data);
}
}
function booleanBasedOperation(engineParams, params, impl) {
engineParams.deflection = DEFLECTION;
if (params.boolean && (<any>BooleanType[params.boolean.type]) > 0) {
engineParams.boolean = {
type: BooleanType[params.boolean.type],
operands: shellsToPointers(params.boolean.operands),
tolerance: E0_TOLERANCE,
}
}
let data = impl(engineParams);
let consumed = [];
if (params.boolean) {
data.consumed.forEach(ptr => {
let model = params.boolean.operands.find(m => managedByE0(m) && m.brepShell.data.externals.ptr === ptr);
if (model) {
consumed.push(model);
}
});
}
return {
consumed,
created: data.created.map(shape => readShellData(shape, consumed, params.csys))
}
}
const mapLoftParams = params => ({
sections: params.sections.map(sec => readSketchContour(sec.contour, sec.face)),
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
});
function createExtrudeCommand(request, ctx, invert) {
const face = ctx.cadRegistry.findFace(request.face);
const paths = readSketch(face, request, ctx.sketchStorageService);
return {
face,
request: {
vector: resolveExtrudeVector(ctx.cadRegistry, face, request, !invert).data(),
sketch: paths,
tolerance: E0_TOLERANCE,
deflection: DEFLECTION,
}
};
}
function createRevolveCommand(request, ctx: ApplicationContext) {
const {cadRegistry, sketchStorageService} = ctx;
const face = cadRegistry.findFace(request.face);
const paths = readSketch(face, request, sketchStorageService);
let pivot = cadRegistry.findSketchObject(request.axis).sketchPrimitive;
let tr = face.csys.outTransformation;
let axisOrigin = tr._apply3(pivot.a.data());
let axisDir = vec._normalize(vec._sub(tr._apply3(pivot.b.data()), axisOrigin))
let res = {
face,
request: {
axisOrigin,
axisDir,
angle: request.angle / 180.0 * Math.PI,
sketch: paths,
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
}
};
// @ts-ignore
if (managedByE0(face.shell) && request.boolean && BooleanType[request.boolean] > 0) {
// @ts-ignore
res.request.boolean = {
type: BooleanType[request.boolean],
operand: (<MBrepShell>face.shell).brepShell.data.externals.ptr
}
}
return res;
}

View file

@ -1,164 +0,0 @@
import {
DEFLECTION, E0_TOLERANCE, managedByE0, readShellData, readSketch, readSketchContour, shellsToPointers,
singleShellRespone,
writeCsys
} from './common';
import {callEngine} from './interact';
import {resolveExtrudeVector} from '../cutExtrude/cutExtrude';
import {MOpenFaceShell} from '../../model/mopenFace';
import {BooleanType} from "engine/api";
export function boolean({type, operandsA, operandsB}) {
let engineParams = {
type: BooleanType[type],
operandsA: shellsToPointers(operandsA),
operandsB: shellsToPointers(operandsB),
tolerance: E0_TOLERANCE,
deflection: DEFLECTION,
};
let data = callEngine(engineParams, Module._SPI_boolean);
let consumed = [...operandsA, ...operandsB];
return {
consumed,
created: [readShellData(data.result, consumed, operandsA[0].csys)]
}
}
export function createBox(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
dx: params.width,
dy: params.height,
dz: params.depth
}, params, Module._SPI_box);
}
export function createTorus(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
r1: params.radius,
r2: params.tube
}, params, Module._SPI_torus);
}
export function createCone(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys, true),
r1: params.radius,
r2: params.frustum,
h: params.height
}, params, Module._SPI_cone);
}
export function createCylinder(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys, true),
r: params.radius,
h: params.height,
}, params, Module._SPI_cylinder);
}
export function createSphere(params) {
return booleanBasedOperation({
csys: writeCsys(params.csys),
r: params.radius,
}, params, Module._SPI_sphere);
}
export function stepImport(params) {
let shape = callEngine({
file: params.file
}, Module._SPI_stepImport);
return {
consumed: [], created: [readShellData(shape, [], undefined)]
}
}
function booleanBasedOperation(engineParams, params, impl) {
engineParams.deflection = DEFLECTION;
if (params.boolean && BooleanType[params.boolean.type] > 0) {
engineParams.boolean = {
type: BooleanType[params.boolean.type],
operands: shellsToPointers(params.boolean.operands),
tolerance: E0_TOLERANCE,
}
}
let data = callEngine(engineParams, impl);
let consumed = [];
if (params.boolean) {
data.consumed.forEach(ptr => {
let model = params.boolean.operands.find(m => managedByE0(m) && m.brepShell.data.externals.ptr === ptr);
if (model) {
consumed.push(model);
}
});
}
return {
consumed,
created: data.created.map(shape => readShellData(shape, consumed, params.csys))
}
}
function cutExtrude(isCut, request) {
function createExtrudeCommand(request, {cadRegistry, sketchStorageService}, invert) {
const face = cadRegistry.findFace(request.face);
const paths = readSketch(face, request, sketchStorageService);
return {
face,
request: {
vector: resolveExtrudeVector(cadRegistry, face, request, !invert).data(),
sketch: paths,
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
}
};
}
let {request: engineReq, face} = createExtrudeCommand(request, services, isCut);
if (managedByE0(face.shell)) {
engineReq.boolean = {
type: isCut ? BooleanType.SUBTRACT : BooleanType.UNION,
operand: face.shell.brepShell.data.externals.ptr
}
}
let data = callEngine(engineReq, Module._SPI_extrude);
return singleShellRespone(face.shell, data);
}
export function cut(params) {
return cutExtrude(true, params);
}
export function extrude(params) {
return cutExtrude(false, params);
}
const mapLoftParams = params => ({
sections: params.sections.map(sec => readSketchContour(sec.contour, sec.face)),
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
});
export function loftPreview(params) {
return callEngine(mapLoftParams(params), Module._SPI_loftPreview);
}
export function loft(params) {
let data = callEngine(mapLoftParams(params), Module._SPI_loft);
let baseShell = params.sections[0].face.shell;
let consumed = params.sections
.filter(s => (!(s.face.shell instanceof MOpenFaceShell) || s.face.sketchLoops.length === 1))
.map(s => s.face.shell);
return {
consumed,
created: [readShellData(data, consumed, baseShell.csys)]
}
}

View file

@ -1,17 +1,14 @@
/**
* This is an internal alternative to native engine. It overrides basic 3d part design operations
*/
import * as craftMethods from './craftMethods';
import operationHandler from './operationHandler';
import {GenericWASMEngine_V1} from "../../../../../modules/engine/impl/wasm/GenericWASMEngine_V1";
import {CraftEngine} from "./craftEngine";
export function activate(ctx) {
loadWasm(ctx);
ctx.services.operation.handlers.push(operationHandler);
ctx.services.craftEngine = {
...craftMethods
};
const wasmEngine = new GenericWASMEngine_V1();
ctx.services.craftEngine = new CraftEngine(wasmEngine, ctx);
ctx.craftEngine = ctx.services.craftEngine;
}

View file

@ -1,88 +0,0 @@
import {DEFLECTION, E0_TOLERANCE, managedByE0, readSketch, singleShellRespone} from './common';
import {BooleanType} from "engine/api";
import {callEngine} from './interact';
import {resolveExtrudeVector} from '../cutExtrude/cutExtrude';
export default function operationHandler(id, request, services) {
switch (id) {
case 'CUT':
case 'EXTRUDE': {
let isCut = id === 'CUT';
let {request: engineReq, face} = createExtrudeCommand(request, services, isCut);
if (managedByE0(face.shell)) {
engineReq.boolean = {
type: isCut ? BooleanType.SUBTRACT : BooleanType.UNION,
operand: face.shell.brepShell.data.externals.ptr
}
}
let data = callEngine(engineReq, Module._SPI_extrude);
return singleShellRespone(face.shell, data);
}
case 'REVOLVE': {
let {request: engineReq, face} = createRevolveCommand(request, services);
let data = callEngine(engineReq, Module._SPI_revolve);
return singleShellRespone(face.shell, data);
}
case 'FILLET': {
let edge = services.cadRegistry.findEdge(request.edges[0]);
let engineReq = {
deflection: DEFLECTION,
solid: edge.shell.brepShell.data.externals.ptr,
edges: request.edges.map(e => ({
edge: services.cadRegistry.findEdge(e).brepEdge.data.externals.ptr,
thickness: request.thickness
}))
};
let data = callEngine(engineReq, Module._SPI_fillet);
return singleShellRespone(edge.shell, data);
}
}
}
function createExtrudeCommand(request, {cadRegistry, sketchStorageService}, invert) {
const face = cadRegistry.findFace(request.face);
const paths = readSketch(face, request, sketchStorageService);
return {
face,
request: {
vector: resolveExtrudeVector(cadRegistry, face, request, !invert).data(),
sketch: paths,
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
}
};
}
function createRevolveCommand(request, {cadRegistry, sketchStorageService}) {
const face = cadRegistry.findFace(request.face);
const paths = readSketch(face, request, sketchStorageService);
let pivot = cadRegistry.findSketchObject(request.axis).sketchPrimitive;
let tr = face.csys.outTransformation;
let vec = __CAD_APP.services.exposure.math.vec;
let axisOrigin = tr._apply3(pivot.a.data());
let axisDir = vec._normalize(vec._sub(tr._apply3(pivot.b.data()), axisOrigin))
let res = {
face,
request: {
axisOrigin,
axisDir,
angle: request.angle / 180.0 * Math.PI,
sketch: paths,
tolerance: E0_TOLERANCE,
deflection: DEFLECTION
}
};
if (managedByE0(face.shell) && request.boolean && BooleanType[request.boolean] > 0) {
res.request.boolean = {
type: BooleanType[request.boolean],
operand: face.shell.brepShell.data.externals.ptr
}
}
return res;
}

View file

@ -8,7 +8,7 @@ export default {
info: 'creates a fillet on selected edges',
paramsInfo: ({edges}) => edges.map(o => o.thikness).join(' ,'),
previewGeomProvider: () => new THREE.Geometry(),
run: (request) => console.dir(request),
run: (request, ctx) => ctx.craftEngine.fillet(request),
form: FilletForm,
schema
};

View file

@ -1,7 +1,6 @@
import RevolveForm from './RevolveForm';
import schema from './schema';
import {createRevolvePreviewGeomProvider, revolvePreviewGeomProvider} from './revolvePreviewer';
import {NOOP} from 'gems/func';
import {revolvePreviewGeomProvider} from './revolvePreviewer';
export default {
id: 'REVOLVE',
@ -10,7 +9,7 @@ export default {
info: 'creates a solid based on revolve surfaces',
paramsInfo: ({angle}) => angle,
previewGeomProvider: revolvePreviewGeomProvider,
run: NOOP,
run: (request, ctx) => ctx.craftEngine.revolve(request),
form: RevolveForm,
schema
};

View file

@ -27,7 +27,7 @@ import * as ExportPlugin from '../exportPlugin';
import * as ExposurePlugin from '../exposure/exposurePlugin';
import * as ViewSyncPlugin from '../scene/viewSyncPlugin';
import * as EntityContextPlugin from '../scene/entityContextPlugin';
import * as E0Plugin from '../craft/e0/e0Plugin';
import * as OCCTPlugin from '../craft/e0/occtPlugin';
import context from 'context';
@ -61,7 +61,7 @@ export default function startApplication(callback) {
CadRegistryPlugin,
ExportPlugin,
ExposurePlugin,
E0Plugin,
OCCTPlugin,
ProjectManagerPlugin
];