@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
261 lines (245 loc) • 8.35 kB
text/typescript
/**
* extrudes CAD primitives
*
*
*/
import {CADSopNode} from './_BaseCAD';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {
OpenCascadeInstance,
gp_Vec,
CadGC,
CadGeometryType,
cadGeometryTypeFromShape,
GCRegisterFunction,
cadDowncast,
TopoDS_Edge,
TopoDS_Wire,
TopoDS_Face,
TopoDS_Shape,
} from '../../../core/geometry/modules/cad/CadCommon';
import {CoreGroup} from '../../../core/geometry/Group';
import {SopType} from '../../poly/registers/nodes/types/Sop';
import {CadLoaderSync} from '../../../core/geometry/modules/cad/CadLoaderSync';
import {CadObject} from '../../../core/geometry/modules/cad/CadObject';
import {isBooleanTrue} from '../../../core/Type';
interface CommonOptions {
oc: OpenCascadeInstance;
r: GCRegisterFunction;
newObjects: CadObject<CadGeometryType>[];
extrudeDir: gp_Vec;
}
class CADExtrudeSopParamsConfig extends NodeParamsConfig {
/** @param direction */
dir = ParamConfig.VECTOR3([0, 1, 0]);
/** @param height */
height = ParamConfig.FLOAT(1, {
range: [-10, 10],
rangeLocked: [false, false],
});
/** @param create caps */
cap = ParamConfig.BOOLEAN(1);
/** @param convert caps to faces */
capsAsFaces = ParamConfig.BOOLEAN(1);
}
const ParamsConfig = new CADExtrudeSopParamsConfig();
export class CADExtrudeSopNode extends CADSopNode<CADExtrudeSopParamsConfig> {
override paramsConfig = ParamsConfig;
static override type() {
return SopType.CAD_EXTRUDE;
}
protected override initializeNode() {
this.io.inputs.setCount(1);
}
override cook(inputCoreGroups: CoreGroup[]) {
const inputCoreGroup = inputCoreGroups[0];
const extrudeDir = CadLoaderSync.gp_Vec;
extrudeDir.SetCoord_2(
this.pv.dir.x * this.pv.height,
this.pv.dir.y * this.pv.height,
this.pv.dir.z * this.pv.height
);
const newObjects: CadObject<CadGeometryType>[] = [];
const inputObjects = inputCoreGroup.cadObjects();
if (inputObjects) {
const oc = CadLoaderSync.oc();
CadGC.withGC((r) => {
const options: CommonOptions = {
oc,
r,
newObjects,
extrudeDir,
};
for (const object of inputObjects) {
this._processObject(object, options);
}
});
}
this.setCADObjects(newObjects);
}
private _processObject(object: CadObject<CadGeometryType>, options: CommonOptions) {
const type = object.type;
switch (type) {
case CadGeometryType.VERTEX: {
return this._processVertexObject(object as CadObject<CadGeometryType.VERTEX>, options);
}
case CadGeometryType.EDGE: {
return this._processEdgeObject(object as CadObject<CadGeometryType.EDGE>, options);
}
case CadGeometryType.WIRE: {
return this._processWireObject(object as CadObject<CadGeometryType.WIRE>, options);
}
case CadGeometryType.FACE: {
return this._processFaceObject(object as CadObject<CadGeometryType.FACE>, options);
}
case CadGeometryType.SHELL: {
return this._processShellObject(object as CadObject<CadGeometryType.SHELL>, options);
}
default: {
return options.newObjects.push(object);
}
}
}
private _processVertexObject(object: CadObject<CadGeometryType.VERTEX>, options: CommonOptions) {
const {oc, r, newObjects, extrudeDir} = options;
const vertex = object.cadGeometry();
const prismApi = r(new oc.BRepPrimAPI_MakePrism_1(vertex, extrudeDir, false, true));
const prism = prismApi.Shape();
const type = cadGeometryTypeFromShape(oc, prism);
if (type) {
const newObject = new CadObject(prism, type);
newObjects.push(newObject);
}
}
private _processEdgeObject(object: CadObject<CadGeometryType.EDGE>, options: CommonOptions) {
const {oc, r, extrudeDir, newObjects} = options;
const edge = object.cadGeometry() as TopoDS_Edge;
const api = r(new oc.BRepPrimAPI_MakePrism_1(edge, extrudeDir, false, true));
const shapes = [api.Shape()];
// if (isBooleanTrue(this.pv.cap)) {
// const addCap = (capShape: TopoDS_Shape | undefined, invert: boolean) => {
// if (!capShape) {
// return;
// }
// console.log('capShape', capShape, cadGeometryTypeFromShape(oc, capShape));
// if (cadGeometryTypeFromShape(oc, capShape) == CadGeometryType.WIRE) {
// const wire = cadDowncast(oc, capShape) as TopoDS_Wire;
// if (isBooleanTrue(this.pv.capsAsFaces)) {
// const capApi = r(new oc.BRepBuilderAPI_MakeFace_15(wire, true));
// if (capApi.IsDone()) {
// const face = capApi.Face();
// shapes.push(invert ? face.Complemented() : face);
// }
// } else {
// shapes.push(capShape);
// }
// }
// };
// addCap(api.FirstShape(), true);
// addCap(api.LastShape(), false);
// }
for (const shape of shapes) {
const type = cadGeometryTypeFromShape(oc, shape);
if (type) {
const newObject = new CadObject(shape, type);
newObjects.push(newObject);
}
}
// convert to a wire
// const api = new oc.BRepBuilderAPI_MakeWire_1();
// const edge = cadDowncast(oc, object.cadGeometry()) as TopoDS_Edge;
// api.Add_1(edge);
// const wire = api.Wire();
// api.delete();
// // process as wire
// this._processWire(wire, options);
}
private _processWireObject(object: CadObject<CadGeometryType.WIRE>, options: CommonOptions) {
const wire = object.cadGeometry();
this._processWire(wire, options);
}
private _processWire(wire: TopoDS_Wire, options: CommonOptions) {
const {oc, r, extrudeDir, newObjects} = options;
const api = r(new oc.BRepPrimAPI_MakePrism_1(wire, extrudeDir, false, true));
const shapes = [api.Shape()];
if (isBooleanTrue(this.pv.cap)) {
const addCap = (capShape: TopoDS_Shape | undefined, invert: boolean) => {
if (!capShape) {
return;
}
if (cadGeometryTypeFromShape(oc, capShape) == CadGeometryType.WIRE) {
const wire = cadDowncast(oc, capShape) as TopoDS_Wire;
if (isBooleanTrue(this.pv.capsAsFaces)) {
const capApi = r(new oc.BRepBuilderAPI_MakeFace_15(wire, true));
if (capApi.IsDone()) {
const face = capApi.Face();
shapes.push(invert ? face.Complemented() : face);
}
} else {
shapes.push(capShape);
}
}
};
addCap(api.FirstShape(), false);
addCap(api.LastShape(), true);
}
for (const shape of shapes) {
const type = cadGeometryTypeFromShape(oc, shape);
if (type) {
const newObject = new CadObject(shape, type);
newObjects.push(newObject);
}
}
// TODO: cad/convert or cad/makeFace
// const faceApi = r(new oc.BRepBuilderAPI_MakeFace_15(wire, true));
// const face = faceApi.Face();
// this._processFace(face, options);
}
private _processFaceObject(object: CadObject<CadGeometryType.FACE>, options: CommonOptions) {
this._processFace(object.cadGeometry(), options);
}
private _processFace(face: TopoDS_Face, options: CommonOptions) {
const {oc, r, newObjects, extrudeDir} = options;
const api = r(new oc.BRepPrimAPI_MakePrism_1(face, extrudeDir, false, true));
const shapes = [api.Shape()];
// if (isBooleanTrue(this.pv.cap)) {
// const addCap = (capShape: TopoDS_Shape | undefined, invert: boolean) => {
// if (!capShape) {
// return;
// }
// if (cadGeometryTypeFromShape(oc, capShape) == CadGeometryType.WIRE) {
// const wire = cadDowncast(oc, capShape) as TopoDS_Wire;
// if (isBooleanTrue(this.pv.capsAsFaces)) {
// const capApi = r(new oc.BRepBuilderAPI_MakeFace_15(wire, true));
// if (capApi.IsDone()) {
// const face = capApi.Face();
// shapes.push(invert ? face.Complemented() : face);
// }
// } else {
// shapes.push(capShape);
// }
// }
// };
// addCap(api.FirstShape(), true);
// addCap(api.LastShape(), false);
// }
for (const shape of shapes) {
const type = cadGeometryTypeFromShape(oc, shape);
if (type) {
const newObject = new CadObject(shape, type);
newObjects.push(newObject);
}
}
}
private _processShellObject(object: CadObject<CadGeometryType.SHELL>, options: CommonOptions) {
const {oc, r, newObjects, extrudeDir} = options;
const shell = object.cadGeometry();
const prismApi = r(new oc.BRepPrimAPI_MakePrism_1(shell, extrudeDir, false, true));
const prism = prismApi.Shape();
const type = cadGeometryTypeFromShape(oc, prism);
if (type) {
const newObject = new CadObject(prism, type);
newObjects.push(newObject);
}
}
}