summaryrefslogtreecommitdiff
path: root/thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp')
-rw-r--r--thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp268
1 files changed, 268 insertions, 0 deletions
diff --git a/thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp b/thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp
new file mode 100644
index 0000000000..9f6987154e
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvmesh/halfedge/Face.cpp
@@ -0,0 +1,268 @@
+// This code is in the public domain -- castanyo@yahoo.es
+
+#include "nvmesh.h" // pch
+
+#include "Face.h"
+#include "Vertex.h"
+
+#include "nvmath/Fitting.h"
+#include "nvmath/Plane.h"
+#include "nvmath/Vector.inl"
+
+#include "nvcore/Array.h"
+
+
+using namespace nv;
+using namespace HalfEdge;
+
+/// Get face area.
+float Face::area() const
+{
+ float area = 0;
+ const Vector3 & v0 = edge->from()->pos;
+
+ for (ConstEdgeIterator it(edges(edge->next)); it.current() != edge->prev; it.advance())
+ {
+ const Edge * e = it.current();
+
+ const Vector3 & v1 = e->vertex->pos;
+ const Vector3 & v2 = e->next->vertex->pos;
+
+ area += length(cross(v1-v0, v2-v0));
+ }
+
+ return area * 0.5f;
+}
+
+float Face::parametricArea() const
+{
+ float area = 0;
+ const Vector2 & v0 = edge->from()->tex;
+
+ for (ConstEdgeIterator it(edges(edge->next)); it.current() != edge->prev; it.advance())
+ {
+ const Edge * e = it.current();
+
+ const Vector2 & v1 = e->vertex->tex;
+ const Vector2 & v2 = e->next->vertex->tex;
+
+ area += triangleArea(v0, v1, v2);
+ }
+
+ return area * 0.5f;
+}
+
+
+/// Get boundary length.
+float Face::boundaryLength() const
+{
+ float bl = 0;
+
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ bl += edge->length();
+ }
+
+ return bl;
+}
+
+
+/// Get face normal.
+Vector3 Face::normal() const
+{
+ Vector3 n(0);
+
+ const Vertex * vertex0 = NULL;
+
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ nvCheck(edge != NULL);
+
+ if (vertex0 == NULL)
+ {
+ vertex0 = edge->vertex;
+ }
+ else if (edge->next->vertex != vertex0)
+ {
+ const HalfEdge::Vertex * vertex1 = edge->from();
+ const HalfEdge::Vertex * vertex2 = edge->to();
+
+ const Vector3 & p0 = vertex0->pos;
+ const Vector3 & p1 = vertex1->pos;
+ const Vector3 & p2 = vertex2->pos;
+
+ Vector3 v10 = p1 - p0;
+ Vector3 v20 = p2 - p0;
+
+ n += cross(v10, v20);
+ }
+ }
+
+ return normalizeSafe(n, Vector3(0, 0, 1), 0.0f);
+
+
+ // Get face points eliminating duplicates.
+ /*Array<Vector3> points(4);
+
+ points.append(m_edge->prev()->from()->pos);
+
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ nvDebugCheck(edge != NULL);
+
+ const Vector3 & p = edge->from()->pos;
+ if (points.back() != p)
+ {
+ points.append(edge->from()->pos);
+ }
+ }
+
+ points.popBack();
+
+ if (points.count() < 3)
+ {
+ // Invalid normal.
+ return Vector3(0.0f);
+ }
+ else
+ {
+ // Compute regular normal.
+ Vector3 normal = normalizeSafe(cross(points[1] - points[0], points[2] - points[0]), Vector3(0.0f), 0.0f);
+
+#pragma NV_MESSAGE("TODO: make sure these three points are not colinear")
+
+ if (points.count() > 3)
+ {
+ // Compute best fitting plane to the points.
+ Plane plane = Fit::bestPlane(points.count(), points.buffer());
+
+ // Adjust normal orientation.
+ if (dot(normal, plane.vector()) > 0) {
+ normal = plane.vector();
+ }
+ else {
+ normal = -plane.vector();
+ }
+ }
+
+ nvDebugCheck(isNormalized(normal));
+ return normal;
+ }*/
+}
+
+Vector3 Face::centroid() const
+{
+ Vector3 sum(0.0f);
+ uint count = 0;
+
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ sum += edge->from()->pos;
+ count++;
+ }
+
+ return sum / float(count);
+}
+
+
+bool Face::isValid() const
+{
+ uint count = 0;
+
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ if (edge->face != this) return false;
+ if (!edge->isValid()) return false;
+ if (!edge->pair->isValid()) return false;
+ count++;
+ }
+
+ if (count < 3) return false;
+
+ return true;
+}
+
+
+// Determine if this face contains the given edge.
+bool Face::contains(const Edge * e) const
+{
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ if(it.current() == e) return true;
+ }
+ return false;
+}
+
+// Returns index in this face of the given edge.
+uint Face::edgeIndex(const Edge * e) const
+{
+ int i = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance(), i++)
+ {
+ if(it.current() == e) return i;
+ }
+ return NIL;
+}
+
+
+Edge * Face::edgeAt(uint idx)
+{
+ int i = 0;
+ for(EdgeIterator it(edges()); !it.isDone(); it.advance(), i++) {
+ if (i == idx) return it.current();
+ }
+ return NULL;
+}
+const Edge * Face::edgeAt(uint idx) const
+{
+ int i = 0;
+ for(ConstEdgeIterator it(edges()); !it.isDone(); it.advance(), i++) {
+ if (i == idx) return it.current();
+ }
+ return NULL;
+}
+
+
+// Count the number of edges in this face.
+uint Face::edgeCount() const
+{
+ uint count = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) { ++count; }
+ return count;
+}
+
+// Determine if this is a boundary face.
+bool Face::isBoundary() const
+{
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ nvDebugCheck(edge->pair != NULL);
+
+ if (edge->pair->face == NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Count the number of boundary edges in the face.
+uint Face::boundaryCount() const
+{
+ uint count = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance())
+ {
+ const Edge * edge = it.current();
+ nvDebugCheck(edge->pair != NULL);
+
+ if (edge->pair->face == NULL) {
+ count++;
+ }
+ }
+ return count;
+}