@bitbybit-dev/occt
Version:
Bit By Bit Developers CAD algorithms using OpenCascade Technology kernel. Run in Node and in Browser.
177 lines (176 loc) • 8.59 kB
JavaScript
import { OCCTBooleans } from "./services/booleans";
import { OCCTGeom } from "./services/geom/geom";
import { OCCTIO } from "./services/io";
import { OCCTOperations } from "./services/operations";
import { OCCTShapes } from "./services/shapes/shapes";
import { OCCTTransforms } from "./services/transforms";
import { OCCTFillets } from "./services/fillets";
import { OCCTShapeFix } from "./services/shape-fix";
export class OCCTService {
constructor(occ, och) {
this.occ = occ;
this.och = och;
this.shapes = new OCCTShapes(occ, och);
this.geom = new OCCTGeom(occ, och);
this.transforms = new OCCTTransforms(occ, och);
this.operations = new OCCTOperations(occ, och);
this.booleans = new OCCTBooleans(occ, och);
this.fillets = new OCCTFillets(occ, och);
this.shapeFix = new OCCTShapeFix(occ, och);
// this.assembly = new OCCTAssembly(occ, och);
this.io = new OCCTIO(occ, och);
}
shapesToMeshes(inputs) {
return inputs.shapes.map(shape => this.shapeToMesh({ shape, precision: inputs.precision, adjustYtoZ: inputs.adjustYtoZ }));
}
shapeToMesh(inputs) {
const faceList = [];
const edgeList = [];
const pointsList = [];
let shapeToUse = inputs.shape;
if (shapeToUse.IsNull())
return { faceList, edgeList, pointsList: [] };
// This could be made optional...
// Clean cached triangulation data for the shape.
// This allows to get lower res models out of higher res that was once computed and cached.
this.occ.BRepTools.Clean(shapeToUse, true);
if (inputs.adjustYtoZ) {
const shapeToUseRotated = this.och.transformsService.rotate({ shape: inputs.shape, axis: [1, 0, 0], angle: -90 });
const shapeMirrored = this.och.transformsService.mirrorAlongNormal({ shape: shapeToUseRotated, origin: [0, 0, 0], normal: [0, 0, 1] });
shapeToUseRotated.delete();
shapeToUse.delete();
shapeToUse = shapeMirrored;
}
// Iterate through the faces and triangulate each one
const triangulations = [];
const faces = this.och.shapeGettersService.getFaces({ shape: shapeToUse });
let incrementalMeshBuilder;
if (faces && faces.length) {
incrementalMeshBuilder = new this.occ.BRepMesh_IncrementalMesh_2(shapeToUse, inputs.precision, false, 0.5, false);
faces.forEach((myFace, faceIndex) => {
const aLocation = new this.occ.TopLoc_Location_1();
const myT = this.occ.BRep_Tool.Triangulation(myFace, aLocation, 0);
if (myT.IsNull()) {
console.error("Encountered Null Face!");
return;
}
const thisFace = {
vertex_coord: [],
normal_coord: [],
uvs: [],
tri_indexes: [],
vertex_coord_vec: [],
number_of_triangles: 0,
center_point: undefined,
center_normal: undefined,
face_index: faceIndex
};
thisFace.center_point = this.och.facesService.pointOnUV({ shape: myFace, paramU: 0.5, paramV: 0.5 });
thisFace.center_normal = this.och.facesService.normalOnUV({ shape: myFace, paramU: 0.5, paramV: 0.5 });
const pc = new this.occ.Poly_Connect_2(myT);
const triangulation = myT.get();
// write vertex buffer
thisFace.vertex_coord = new Array(triangulation.NbNodes() * 3);
thisFace.vertex_coord_vec = [];
for (let i = 0; i < triangulation.NbNodes(); i++) {
const p = triangulation.Node(i + 1).Transformed(aLocation.Transformation());
const uv = triangulation.UVNode(i + 1);
thisFace.uvs[(i * 2) + 0] = uv.X();
thisFace.uvs[(i * 2) + 1] = uv.Y();
thisFace.vertex_coord[(i * 3) + 0] = p.X();
thisFace.vertex_coord[(i * 3) + 1] = p.Y();
thisFace.vertex_coord[(i * 3) + 2] = p.Z();
thisFace.vertex_coord_vec.push([p.X(), p.Y(), p.Z()]);
}
// write normal buffer
const myNormal = new this.occ.TColgp_Array1OfDir_2(1, triangulation.NbNodes());
this.occ.StdPrs_ToolTriangulatedShape.Normal(myFace, pc, myNormal);
thisFace.normal_coord = new Array(myNormal.Length() * 3);
for (let i = 0; i < myNormal.Length(); i++) {
const d = myNormal.Value(i + 1);
thisFace.normal_coord[(i * 3) + 0] = d.X();
thisFace.normal_coord[(i * 3) + 1] = d.Y();
thisFace.normal_coord[(i * 3) + 2] = d.Z();
}
// write triangle buffer
const orient = myFace.Orientation_1();
const triangles = myT.get().Triangles();
thisFace.tri_indexes = new Array(triangles.Length() * 3);
let validFaceTriCount = 0;
for (let nt = 1; nt <= myT.get().NbTriangles(); nt++) {
const t = triangles.Value(nt);
let n1 = t.Value(1);
let n2 = t.Value(2);
const n3 = t.Value(3);
if (orient !== this.occ.TopAbs_Orientation.TopAbs_FORWARD) {
const tmp = n1;
n1 = n2;
n2 = tmp;
}
thisFace.tri_indexes[(validFaceTriCount * 3) + 0] = n1 - 1;
thisFace.tri_indexes[(validFaceTriCount * 3) + 1] = n2 - 1;
thisFace.tri_indexes[(validFaceTriCount * 3) + 2] = n3 - 1;
validFaceTriCount++;
}
thisFace.number_of_triangles = validFaceTriCount;
faceList.push(thisFace);
triangulations.push(myT);
aLocation.delete();
myNormal.delete();
triangles.delete();
pc.delete();
});
}
// Nullify Triangulations between runs so they're not stored in the cache
for (let i = 0; i < triangulations.length; i++) {
triangulations[i].Nullify();
triangulations[i].delete();
}
// Get the free edges that aren't on any triangulated face/surface
const edges = this.och.shapeGettersService.getEdges({ shape: shapeToUse });
edges.forEach((myEdge, index) => {
const thisEdge = {
vertex_coord: [],
middle_point: undefined,
edge_index: -1
};
thisEdge.middle_point = this.och.edgesService.pointOnEdgeAtParam({ shape: myEdge, param: 0.5 });
const aLocation = new this.occ.TopLoc_Location_1();
const adaptorCurve = new this.occ.BRepAdaptor_Curve_2(myEdge);
const tangDef = new this.occ.GCPnts_TangentialDeflection_2(adaptorCurve, inputs.precision, 0.1, 2, 1.0e-9, 1.0e-7);
// write vertex buffer
thisEdge.vertex_coord = [];
const nrPoints = tangDef.NbPoints();
const tangDefValues = [];
for (let j = 0; j < nrPoints; j++) {
const tangDefVal = tangDef.Value(j + 1);
thisEdge.vertex_coord.push([
tangDefVal.X(),
tangDefVal.Y(),
tangDefVal.Z()
]);
tangDefValues.push(tangDefVal);
}
thisEdge.edge_index = index;
edgeList.push(thisEdge);
tangDefValues.forEach(v => v.delete());
aLocation.delete();
adaptorCurve.delete();
tangDef.delete();
this.occ.BRepTools.Clean(myEdge, true);
});
const vertices = this.och.shapeGettersService.getVertices({ shape: shapeToUse });
if (vertices.length > 0) {
vertices.forEach(v => {
const pt = this.occ.BRep_Tool.Pnt(v);
pointsList.push([pt.X(), pt.Y(), pt.Z()]);
pt.delete();
});
}
if (incrementalMeshBuilder) {
incrementalMeshBuilder.Delete();
}
this.occ.BRepTools.Clean(shapeToUse, true);
return { faceList, edgeList, pointsList };
}
}