/// <summary> /// Compute the orthonormal bases of the specified face. /// </summary> /// <returns>Array containing the 2 Vector3d.</returns> /// <param name="face">Face.</param> public static Vector3d[] OrthonormalBases(MeshFace face) { var e1 = Vector(face.HalfEdge).Unit(); var normal = FaceNormal(face); var e2 = normal.Cross(e1); return(new[] { e1, e2 }); }
/// <summary> /// Compute the normal vector of the specified face. /// </summary> /// <returns>The normal.</returns> /// <param name="face">Face.</param> public static Vector3d FaceNormal(MeshFace face) { if (face.IsBoundaryLoop()) { return(null); } var u = Vector(face.HalfEdge); var v = -Vector(face.HalfEdge.Prev); return(u.Cross(v).Unit()); }
/// <summary> /// Computes the area of the specified face. /// </summary> /// <returns>The face area.</returns> /// <param name="face">Face.</param> public static double Area(MeshFace face) { if (face.IsBoundaryLoop()) { return(0.0); } var u = Vector(face.HalfEdge); var v = -Vector(face.HalfEdge.Prev); return(0.5 * u.Cross(v).Length); }
/// <summary> /// Compute the centroid of the specified face. /// </summary> /// <returns>The centroid.</returns> /// <param name="face">Face.</param> public static Point3d Centroid(MeshFace face) { var hE = face.HalfEdge; Point3d a = hE.Vertex; Point3d b = hE.Next.Vertex; Point3d c = hE.Prev.Vertex; if (face.IsBoundaryLoop()) { return((a + b) / 2); } return((a + b + c) / 3); }
/// <summary> /// Compute the circumcenter the specified face. /// </summary> /// <returns>The circumcenter.</returns> /// <param name="face">Face.</param> public static Point3d Circumcenter(MeshFace face) { var hE = face.HalfEdge; Point3d a = hE.Vertex; Point3d b = hE.Next.Vertex; Point3d c = hE.Prev.Vertex; if (face.IsBoundaryLoop()) { return((a + b) / 2); } var ac = c - a; var ab = b - a; var w = ab.Cross(ac); var u = w.Cross(ab) * ac.LengthSquared; var v = ac.Cross(w) * ab.LengthSquared; var x = ( Point3d )(u + v) / (2 * w.LengthSquared); return(x + a); }
// Takes a List containing another List per face with the vertex indexes belonging to that face private bool CreateFaces(IEnumerable <List <int> > faceIndexes) { var edgeCount = new Dictionary <string, int>(); var existingHalfEdges = new Dictionary <string, MeshHalfEdge>(); var hasTwinHalfEdge = new Dictionary <MeshHalfEdge, bool>(); // Create the faces, edges and half-edges, non-boundary loops and link references when possible; foreach (var indexes in faceIndexes) { var f = new MeshFace(); this.Faces.Add(f); var tempHEdges = new List <MeshHalfEdge>(indexes.Count); // Create empty half-edges for (var i = 0; i < indexes.Count; i++) { var h = new MeshHalfEdge(); tempHEdges.Add(h); } // Fill out each half edge for (var i = 0; i < indexes.Count; i++) { // Edge goes from v0 to v1 var v0 = indexes[i]; var v1 = indexes[(i + 1) % indexes.Count]; var h = tempHEdges[i]; // Set previous and next h.Next = tempHEdges[(i + 1) % indexes.Count]; h.Prev = tempHEdges[(i + indexes.Count - 1) % indexes.Count]; h.OnBoundary = false; hasTwinHalfEdge.Add(h, false); // Set half-edge & vertex mutually h.Vertex = this.Vertices[v0]; this.Vertices[v0].HalfEdge = h; // Set half-edge face & vice versa h.Face = f; f.HalfEdge = h; // Reverse v0 and v1 if v0 > v1 if (v0 > v1) { var temp = v0; v0 = v1; v1 = temp; } var key = v0 + " " + v1; if (existingHalfEdges.ContainsKey(key)) { // If this half-edge key already exists, it is the twin of this current half-edge var twin = existingHalfEdges[key]; h.Twin = twin; twin.Twin = h; h.Edge = twin.Edge; hasTwinHalfEdge[h] = true; hasTwinHalfEdge[twin] = true; edgeCount[key]++; } else { // Create an edge and set its half-edge var e = new MeshEdge(); this.Edges.Add(e); h.Edge = e; e.HalfEdge = h; // Record the newly created half-edge existingHalfEdges.Add(key, h); edgeCount.Add(key, 1); } } this.HalfEdges.AddRange(tempHEdges); } // Create boundary edges for (var i = 0; i < this.HalfEdges.Count; i++) { var h = this.HalfEdges[i]; if (!hasTwinHalfEdge[h]) { var f = new MeshFace(); this.Boundaries.Add(f); var boundaryCycle = new List <MeshHalfEdge>(); var halfEdge = h; do { var boundaryHalfEdge = new MeshHalfEdge(); this.HalfEdges.Add(boundaryHalfEdge); boundaryCycle.Add(boundaryHalfEdge); var nextHalfEdge = halfEdge.Next; while (hasTwinHalfEdge[nextHalfEdge]) { nextHalfEdge = nextHalfEdge.Twin.Next; } boundaryHalfEdge.Vertex = nextHalfEdge.Vertex; boundaryHalfEdge.Edge = halfEdge.Edge; boundaryHalfEdge.OnBoundary = true; boundaryHalfEdge.Face = f; f.HalfEdge = boundaryHalfEdge; boundaryHalfEdge.Twin = halfEdge; halfEdge.Twin = boundaryHalfEdge; halfEdge = nextHalfEdge; } while (halfEdge != h); var n = boundaryCycle.Count; for (var j = 0; j < n; j++) { boundaryCycle[j].Next = boundaryCycle[(j + n - 1) % n]; boundaryCycle[j].Prev = boundaryCycle[(j + 1) % n]; hasTwinHalfEdge[boundaryCycle[j]] = true; hasTwinHalfEdge[boundaryCycle[j].Twin] = true; } } if (h.OnBoundary) { continue; } var corner = new MeshCorner { HalfEdge = h }; h.Corner = corner; this.Corners.Add(corner); } // Check mesh for common errors if (this.HasIsolatedFaces() || this.HasIsolatedVertices() || this.HasNonManifoldEdges()) { return(false); } // Index elements this.IndexElements(); return(true); }