void netGenTriangulation(const TopoDS_Shape& thShape,
PolyMesh& theMesh)
{
Bnd_Box aabb;
BRepBndLib::Add(thShape, aabb, false);
const double diag = std::sqrt(aabb.SquareExtent());
std::cout << "diag of shape: " << diag << std::endl;
netgen::MeshingParameters& mp = netgen::mparam;
mp.minh = 0.0;
mp.maxh = 0.05 * diag;
mp.uselocalh = true;
mp.secondorder = false;
mp.grading = 0.3;
nglib::Ng_Init();
netgen::OCCGeometry occgeo;
occgeo.shape = thShape;
occgeo.changed = 1;
occgeo.BuildFMap();
occgeo.CalcBoundingBox();
// Resulting mesh.
netgen::Mesh ngMesh;
// Mesh building
netgen::OCCSetLocalMeshSize(occgeo, ngMesh);
netgen::OCCFindEdges(occgeo, ngMesh);
netgen::OCCMeshSurface(occgeo, ngMesh, netgen::MESHCONST_OPTSURFACE);
const int nbNodes = (int)ngMesh.GetNP();
const int nbTriangles = (int)ngMesh.GetNSE();
for (int i = 1; i <= nbNodes; ++i)
{
const netgen::MeshPoint& point = ngMesh.Point(netgen::PointIndex(i));
PolyMesh::VertexHandle vh = theMesh.add_vertex(PolyMesh::Point(point[0], point[1], point[2]));
}
for (int i = 1; i <= nbTriangles; ++i)
{
const netgen::Element2d& elem = ngMesh.SurfaceElement(netgen::ElementIndex(i));
if (elem.GetNP() == 3)
{
PolyMesh::FaceHandle fh = theMesh.add_face(
PolyMesh::VertexHandle(elem[0] - 1),
PolyMesh::VertexHandle(elem[1] - 1),
PolyMesh::VertexHandle(elem[2] - 1));
}
if (elem.GetNP() == 4)
{
PolyMesh::FaceHandle fh = theMesh.add_face(
PolyMesh::VertexHandle(elem[0] - 1),
PolyMesh::VertexHandle(elem[1] - 1),
PolyMesh::VertexHandle(elem[2] - 1),
PolyMesh::VertexHandle(elem[3] - 1));
}
}
ngMesh.DeleteMesh();
nglib::Ng_Exit();
std::cout << "number of netgen nodes: " << nbNodes << std::endl;
std::cout << "number of netgen trias: " << nbTriangles << std::endl;
std::cout << "netgen triangulation finish" << std::endl;
}
double getDistance(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& vh1,
const PolyMesh::VertexHandle& vh2)
{
OpenMesh::Vec3f p1 = theMesh.point(vh1);
OpenMesh::Vec3f p2 = theMesh.point(vh2);
double distace = (p2 - p1).norm();
return distace;
}
double getAngle(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& v1,
const PolyMesh::VertexHandle& v2,
const PolyMesh::VertexHandle& v3)
{
PolyMesh::Normal v2v1 = theMesh.point(v1) - theMesh.point(v2);
PolyMesh::Normal v2v3 = theMesh.point(v3) - theMesh.point(v2);
v2v1.normalize();
v2v3.normalize();
double dot = v2v1 | v2v3;
// consider the calculation precision
if (dot > 1.0)
return 0.0;
if (dot < -1.0)
return 180.0;
double angle = std::acos(dot);
return angle * 180.0 / M_PI;
}
double getArea(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& v1,
const PolyMesh::VertexHandle& v2,
const PolyMesh::VertexHandle& v3)
{
double d1 = getDistance(theMesh, v1, v2);
double d2 = getDistance(theMesh, v2, v3);
double d3 = getDistance(theMesh, v1, v3);
double d = (d1 + d2 + d3) / 2.0;
double area = sqrt(d*(d - d1)*(d - d2)*(d - d3));
return area;
}
double getTriaArea(const PolyMesh& theMesh,
const PolyMesh::FaceHandle& fh)
{
PolyMesh::HalfedgeHandle heh = theMesh.halfedge_handle(fh);
PolyMesh::VertexHandle vh1 = theMesh.to_vertex_handle(heh);
PolyMesh::VertexHandle vh2 = theMesh.to_vertex_handle(theMesh.next_halfedge_handle(heh));
PolyMesh::VertexHandle vh3 =
theMesh.to_vertex_handle(theMesh.next_halfedge_handle(theMesh.next_halfedge_handle(heh)));
return getArea(theMesh, vh1, vh2, vh3);
}
double getTriaQualityFactor(const PolyMesh& theMesh,
const PolyMesh::FaceHandle& fh)
{
PolyMesh::HalfedgeHandle heh = theMesh.halfedge_handle(fh);
PolyMesh::VertexHandle vh1 = theMesh.to_vertex_handle(heh);
PolyMesh::VertexHandle vh2 = theMesh.to_vertex_handle(theMesh.next_halfedge_handle(heh));
PolyMesh::VertexHandle vh3 =
theMesh.to_vertex_handle(theMesh.next_halfedge_handle(theMesh.next_halfedge_handle(heh)));
return getTriaQualityFactor(theMesh, vh1, vh2, vh3);
}
double getTriaQualityFactor(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& v1,
const PolyMesh::VertexHandle& v2,
const PolyMesh::VertexHandle& v3)
{
double d1 = getDistance(theMesh, v1, v2);
double d2 = getDistance(theMesh, v2, v3);
double d3 = getDistance(theMesh, v1, v3);
double d = (d1 + d2 + d3) / 2.0;
double area = sqrt(d*(d - d1)*(d - d2)*(d - d3));
return area * 4.0 * 1.7320508 / (d1*d1+d2*d2+d3*d3);
}
double getQuadQualityFactor(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& v1,
const PolyMesh::VertexHandle& v2,
const PolyMesh::VertexHandle& v3,
const PolyMesh::VertexHandle& v4)
{
double triaQuality1 = getTriaQualityFactor(theMesh, v1, v2, v3);
double triaQuality2 = getTriaQualityFactor(theMesh, v1, v2, v4);
double triaQuality3 = getTriaQualityFactor(theMesh, v3, v4, v2);
double triaQuality4 = getTriaQualityFactor(theMesh, v3, v4, v1);
std::vector<double> triaQualities = { triaQuality1 ,triaQuality2, triaQuality3, triaQuality4};
std::sort(triaQualities.begin(), triaQualities.end(), std::greater<double>());
return triaQualities[2] * triaQualities[3] / triaQualities[0] / triaQualities[1];
}
double getFaceAngle(const PolyMesh& theMesh,
const PolyMesh::VertexHandle& v1,
const PolyMesh::VertexHandle& v2,
const PolyMesh::VertexHandle& v3,
const PolyMesh::VertexHandle& v4)
{
// Calculate the Angle between the triangular faces formed by v1, v2, v3
// and the triangular faces formed by v2, v1, v4
// If v3, v4 are in the same plane as v1, v2,
// return 0 if v3, v4 are on the same side of v1, v2 and return 180 on different sides
PolyMesh::Point p1 = theMesh.point(v1);
PolyMesh::Point p2 = theMesh.point(v2);
PolyMesh::Point p3 = theMesh.point(v3);
PolyMesh::Point p4 = theMesh.point(v4);
PolyMesh::Normal n1 = (p1 - p3) % (p2 - p3);
n1.normalize();
PolyMesh::Normal n2 = (p2 - p4) % (p1 - p4);
n2.normalize();
double dot = n1 | n2;
if (dot > 1.0)
return 180.0;
if (dot < -1.0)
return 0.0;
double angle = std::acos(dot);
double rs = 180.0 - angle * 180.0 / M_PI;
return rs;
}
bool checkVetexConnection(PolyMesh& theMesh,
const PolyMesh::VertexHandle& vh1,
const PolyMesh::VertexHandle& vh2)
{
// Iterate over the neighboring vertex of vertex 1
for (PolyMesh::VertexVertexIter vv_it = theMesh.vv_begin(vh1); vv_it != theMesh.vv_end(vh1); ++vv_it)
{
PolyMesh::VertexHandle vh = *vv_it;
if (vh == vh2)
{
return true;
}
}
return false;
}
bool checkIsolatedTriangle(PolyMesh& theMesh)
{
// Count the number of triangular faces
int numTriangles = 0;
for (PolyMesh::FaceIter f_it = theMesh.faces_begin(); f_it != theMesh.faces_end(); ++f_it)
{
PolyMesh::FaceHandle fh = *f_it;
if (theMesh.valence(fh) == 3)
{
numTriangles++;
}
}
// if the number of triangular faces is zero, return false
if (numTriangles == 0)
{
return false;
}
// Count the number of edges adjacent to only one triangular face
// and compare to the number of triangular faces
int numEdgesWithOneTriangle = 0;
// Iterate over all edges
for (PolyMesh::EdgeIter e_it = theMesh.edges_begin(); e_it != theMesh.edges_end(); ++e_it)
{
PolyMesh::EdgeHandle eh = *e_it;
// obtain the two face_handles of the edge
PolyMesh::HalfedgeHandle heh1 = theMesh.halfedge_handle(eh, 0);
PolyMesh::HalfedgeHandle heh2 = theMesh.halfedge_handle(eh, 1);
PolyMesh::FaceHandle fh1 = theMesh.face_handle(heh1);
PolyMesh::FaceHandle fh2 = theMesh.face_handle(heh2);
// if the first is tria face and another is quad face or invalid
if (fh1.is_valid() && theMesh.valence(fh1) == 3 &&
(!fh2.is_valid() || (fh2.is_valid() && theMesh.valence(fh2) == 4)))
{
numEdgesWithOneTriangle++;
}
else if (fh2.is_valid() && theMesh.valence(fh2) == 3 &&
(!fh1.is_valid() || (fh1.is_valid() && theMesh.valence(fh1) == 4)))
{
numEdgesWithOneTriangle++;
}
}
if (numEdgesWithOneTriangle != numTriangles * 3)
{
return true;
}
else
{
return false;
}
}