triangulation_triangulate.js
import oc from "../opencascade/initializer";
import {Solid, Face, Edge, Wire} from "../modeling";
/**
* Triangulates an entity (Solid, Face, Wire, or Edge) into a three.js compatible mesh.
* @memberof triangulation
* @alias triangulate
* @param {Object} parameters - Triangulation parameters.
* @param {Solid|Face|Wire|Edge} parameters.entity - The entity to triangulate.
* @param {number} [parameters.linearTolerance=0.1] - The linear tolerance for triangulation (default is 0.1).
* @param {number} [parameters.angularTolerance=0.1] - The angular tolerance for triangulation (default is 0.1).
* @returns {Object} An object containing positions, normals, and indexes for the mesh.
*/
const triangulate = ({entity, linearTolerance = 0.1, angularTolerance = 0.1}) => {
if (entity instanceof Solid) {
return solidToMesh({solid: entity, linearTolerance, angularTolerance});
} else if (entity instanceof Face) {
return profileToMesh({profile: entity, linearTolerance, angularTolerance});
} else if (entity instanceof Wire) {
return wireToMesh({wire: entity, angularTolerance});
} else if (entity instanceof Edge) {
return edgeToMesh({edge: entity, angularTolerance});
}
};
const solidToMesh = ({solid, linearTolerance, angularTolerance}) => {
new oc.BRepMesh_IncrementalMesh_2(solid.wrapped, linearTolerance, false, angularTolerance, false);
const positions = [];
const normals = [];
const indexes = [];
solid.faces.forEach((face) => {
const triangulation = triangulateFace({face, startIndex: positions.length / 3});
positions.push(...triangulation.positions);
normals.push(...triangulation.normals);
indexes.push(...triangulation.indexes);
});
return {
positions: new Float32Array(positions),
normals: new Float32Array(normals),
indexes: new Uint32Array(indexes),
};
};
const profileToMesh = ({profile, linearTolerance, angularTolerance}) => {
new oc.BRepMesh_IncrementalMesh_2(profile.wrapped, linearTolerance, false, angularTolerance, false);
const triangulation = triangulateFace({face: profile, startIndex: 0});
return {
positions: new Float32Array(triangulation.positions),
normals: new Float32Array(triangulation.normals),
indexes: new Uint32Array(triangulation.indexes),
};
};
const wireToMesh = ({wire, angularTolerance}) => {
const positions = [];
wire.edges.forEach((edge) => {
const triangulation = triangulateEdge({edge, angularTolerance});
positions.push(...triangulation.positions);
});
return {
positions: new Float32Array(positions),
};
};
const edgeToMesh = ({edge, angularTolerance}) => {
return {positions: new Float32Array(triangulateEdge({edge, angularTolerance}).positions)};
};
const triangulateEdge = ({edge, angularTolerance}) => {
const positions = [];
const curve = new oc.BRepAdaptor_Curve_2(edge.wrapped);
const tangentialDeflection = new oc.GCPnts_TangentialDeflection_2(curve, angularTolerance, angularTolerance, 2, 1e-9, 1e-7);
for (let i = 1; i < tangentialDeflection.NbPoints(); i++) {
const previous = tangentialDeflection.Value(i);
const current = tangentialDeflection.Value(i + 1);
positions.push(previous.X(), previous.Y(), previous.Z());
positions.push(current.X(), current.Y(), current.Z());
}
return {positions: positions};
};
const triangulateFace = ({face, startIndex}) => {
const positions = [];
const normals = [];
const indexes = [];
let location = new oc.TopLoc_Location_1();
// the next line also updates the value of the location
let triangulation = oc.BRep_Tool.Triangulation(face.wrapped, location, 0);
// this updates the triangulation object with normals
// oc.Poly.ComputeNormals(triangulation);
const transformation = location.Transformation();
const triangles = triangulation.get();
triangles.ComputeNormals();
const nodesLength = triangles.NbNodes();
for (let index = 0; index < nodesLength; index++) {
const point = triangles.Node(index + 1).Transformed(transformation);
positions[index * 3 + 0] = point.X();
positions[index * 3 + 1] = point.Y();
positions[index * 3 + 2] = point.Z();
const direction = triangles.Normal_1(index + 1).Transformed(transformation);
if (!(face.wrapped.Orientation_1() === oc.TopAbs_Orientation.TopAbs_FORWARD)) {
direction.Reverse();
}
normals[index * 3 + 0] = direction.X();
normals[index * 3 + 1] = direction.Y();
normals[index * 3 + 2] = direction.Z();
}
const trianglesLength = triangles.NbTriangles();
for (let index = 0; index < trianglesLength; index++) {
const triangle = triangles.Triangle(index + 1);
let n1 = triangle.Value(1);
let n2 = triangle.Value(2);
let n3 = triangle.Value(3);
if (!(face.wrapped.Orientation_1() === oc.TopAbs_Orientation.TopAbs_FORWARD)) {
[n1, n2] = [n2, n1]; // swap n1 and n2 values
}
indexes[index * 3 + 0] = n1 - 1 + startIndex;
indexes[index * 3 + 1] = n2 - 1 + startIndex;
indexes[index * 3 + 2] = n3 - 1 + startIndex;
}
return {positions, normals, indexes};
};
export {triangulate};