Exemple #1
0
        /// <summary>
        /// Calculates the midpoint of the specifiec edge.
        /// </summary>
        /// <returns>The point.</returns>
        /// <param name="edge">Edge.</param>
        public static Point3d MidPoint(MeshEdge edge)
        {
            MeshHalfEdge halfEdge = edge.HalfEdge;
            Point3d      a        = halfEdge.Vertex;
            Point3d      b        = halfEdge.Twin.Vertex;

            return((a + b) / 2);
        }
Exemple #2
0
        /// <summary>
        ///     Computes the cotangent of the angle opposite to a half-edge.
        /// </summary>
        /// <returns>The cotangent value.</returns>
        /// <param name="hE">The half-edge</param>
        public static double Cotan(MeshHalfEdge hE)
        {
            if (hE.OnBoundary)
            {
                return(0.0);
            }

            var u = Vector(hE.Prev);
            var v = -Vector(hE.Next);

            return(u.Dot(v) / u.Cross(v).Length);
        }
Exemple #3
0
        /// <summary>
        /// Compute the centroid of the specified face.
        /// </summary>
        /// <returns>The centroid.</returns>
        /// <param name="face">Face.</param>
        public static Point3d Centroid(MeshFace face)
        {
            MeshHalfEdge 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);
        }
Exemple #4
0
        /// <summary>
        ///     Computes the signed angle (in radians) between the faces adjacent to the specified half-edge.
        /// </summary>
        /// <returns>The angle (in radians) between faces.</returns>
        /// <param name="hE">H e.</param>
        public static double DihedralAngle(MeshHalfEdge hE)
        {
            if (hE.OnBoundary || hE.Twin.OnBoundary)
            {
                return(0.0);
            }

            var n1 = FaceNormal(hE.Face);
            var n2 = FaceNormal(hE.Twin.Face);
            var w  = Vector(hE).Unit();

            var cosTheta = n1.Dot(n2);
            var sinTheta = n1.Cross(n2).Dot(w);

            return(Math.Atan2(sinTheta, cosTheta));
        }
Exemple #5
0
        /// <summary>
        /// Compute the circumcenter the specified face.
        /// </summary>
        /// <returns>The circumcenter.</returns>
        /// <param name="face">Face.</param>
        public static Point3d Circumcenter(MeshFace face)
        {
            MeshHalfEdge hE = face.HalfEdge;

            Point3d a = hE.Vertex;
            Point3d b = hE.Next.Vertex;
            Point3d c = hE.Prev.Vertex;

            if (face.IsBoundaryLoop())
            {
                return((a + b) / 2);
            }

            Vector3d ac = c - a;
            Vector3d ab = b - a;
            Vector3d w  = ab.Cross(ac);

            Vector3d u = w.Cross(ab) * ac.LengthSquared;
            Vector3d v = ac.Cross(w) * ab.LengthSquared;

            Point3d x = (Point3d)(u + v) / (2 * w.LengthSquared);

            return(x + a);
        }
Exemple #6
0
 /// <summary>
 ///     Calculate the vector of a specified half-edge.
 /// </summary>
 /// <returns>The half-edge vector.</returns>
 /// <param name="halfEdge">Half edge.</param>
 public static Vector3d Vector(MeshHalfEdge halfEdge) =>
 halfEdge.Vertex - halfEdge.Next.Vertex;
Exemple #7
0
        // 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);
        }