예제 #1
0
        /// <summary>
        /// Calculates and saves the normal of the Face into its FaceData.
        /// </summary>
        /// <param name="faceOuterVertices">All vertices of the outer boundary of the Face.</param>
        /// <param name="face">The Face the normal belongs to.</param>
        public void SetFaceNormal(IList <Vertex> faceOuterVertices, Face face)
        {
            var normal = GeometricOperations.CalculateFaceNormal(faceOuterVertices);

            var cur      = DictFaces[face.Handle];
            var faceData = face.FaceData;

            faceData.FaceNormal    = normal;
            cur.FaceData           = faceData;
            DictFaces[face.Handle] = cur;
        }
예제 #2
0
        private static Dictionary <int, Vertex> GetFaceVertices(Geometry geometry)
        {
            var allFaces        = geometry.GetAllFaces();
            var allFaceVertices = new Dictionary <int, Vertex>();

            foreach (var face in allFaces)
            {
                var faceVertices = geometry.GetFaceVertices(face.Handle).ToList();
                var tempVertex   = new Vertex(face.Handle, GeometricOperations.GetVerticesMeanPos(faceVertices));
                allFaceVertices.Add(face.Handle, tempVertex);
            }
            return(allFaceVertices);
        }
예제 #3
0
        private static void CreateTopSurface(Geometry geometry, float zOffset, bool exturdeAlongNormal)
        {
            //Clone front face.
            var backface = geometry.CloneGeometry();

            if (!exturdeAlongNormal)
            {
                //Add zOffset to each vertex coordinate.
                UpdateVertexZCoord(backface, zOffset);
            }
            else
            {
                var unbounded = backface.GetFaceVertices(1).ToList();
                var normal    = GeometricOperations.CalculateFaceNormal(unbounded);
                UpdateVertexZCoord(backface, unbounded, normal, zOffset);
            }

            Join2DGeometries(geometry, backface);
        }
예제 #4
0
        private static Dictionary <int, Vertex> GetEdgeVertices(Geometry geometry, Dictionary <int, Vertex> faceVertices)
        {
            var allEdges = geometry.GetAllHalfEdges();

            var doneHe = new int[allEdges.Count() + 1];

            var allEdgeVertices = new Dictionary <int, Vertex>();

            foreach (var edge in allEdges)
            {
                if (doneHe[edge.Handle] == edge.TwinHalfEdge)
                {
                    continue;
                }
                var face1 = edge.IncidentFace;
                var twin  = geometry.GetHalfEdgeByHandle(edge.TwinHalfEdge);
                var face2 = twin.IncidentFace;

                var vertex1 = geometry.GetVertexByHandle(edge.OriginVertex);
                var vertex2 = geometry.GetVertexByHandle(twin.OriginVertex);

                var cVertex1 = faceVertices[face1];
                var cVertex2 = faceVertices[face2];

                var temp = new List <Vertex> {
                    vertex1, vertex2, cVertex1, cVertex2
                };

                var finalVertex = new Vertex(edge.Handle, GeometricOperations.GetVerticesMeanPos(temp))
                {
                    IncidentHalfEdge = edge.Handle
                };

                allEdgeVertices.Add(edge.Handle, finalVertex);
                doneHe[edge.TwinHalfEdge] = edge.Handle;
            }
            return(allEdgeVertices);
        }
예제 #5
0
        private static Geometry ExtrudeFaceByHandle(Geometry geometry, int faceHandle, float offset, float3 extrusionVector)
        {
            var face = geometry.GetFaceByHandle(faceHandle);

            //get HE of Face
            var start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            var next  = start;

            var vertexIncHe     = new Dictionary <int, List <HalfEdge> >();
            var allFaceVertices = geometry.GetFaceVertices(faceHandle);

            foreach (var vertex in allFaceVertices)
            {
                vertexIncHe.Add(vertex.Handle, geometry.GetVertexStartingHalfEdges(vertex.Handle).ToList());
            }
            var allH2NEdges = new List <HalfEdge>();

            do
            {
                var nextOriginV = geometry.GetVertexByHandle(next.OriginVertex);
                var newVertex   = new Vertex(geometry.CreateVertHandleId(), nextOriginV.VertData.Pos);

                var twinEdge     = geometry.GetHalfEdgeByHandle(next.TwinHalfEdge);
                var prevEdge     = geometry.GetHalfEdgeByHandle(next.PrevHalfEdge);
                var prevTwinEdge = geometry.GetHalfEdgeByHandle(prevEdge.TwinHalfEdge);

                nextOriginV.VertData.Pos = nextOriginV.VertData.Pos + extrusionVector * offset;

                var h4  = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var h2n = new HalfEdge(geometry.CreateHalfEdgeHandleId());

                var h1 = new HalfEdge(geometry.CreateHalfEdgeHandleId());

                var currentList = vertexIncHe[nextOriginV.Handle];
                foreach (var halfEdge in currentList)
                {
                    if (halfEdge == next)
                    {
                        continue;
                    }
                    var edge = GeomEditing.UpdateHalfEdgeOrigin(halfEdge, newVertex.Handle);
                    geometry.ReplaceHalfEdge(edge);
                }

                nextOriginV.IncidentHalfEdge = next.Handle;

                h4.OriginVertex  = nextOriginV.Handle;
                h2n.OriginVertex = newVertex.Handle;
                h1.OriginVertex  = newVertex.Handle;

                h4.TwinHalfEdge  = h2n.Handle;
                h2n.TwinHalfEdge = h4.Handle;

                h4.NextHalfEdge = h1.Handle;
                h1.PrevHalfEdge = h4.Handle;

                h1.TwinHalfEdge       = next.TwinHalfEdge;
                twinEdge.TwinHalfEdge = h1.Handle;

                prevTwinEdge.OriginVertex = newVertex.Handle;

                newVertex.IncidentHalfEdge = h2n.Handle;

                geometry.ReplaceHalfEdge(twinEdge);
                geometry.ReplaceHalfEdge(prevTwinEdge);
                geometry.ReplaceVertex(nextOriginV);
                geometry.DictVertices.Add(newVertex.Handle, newVertex);
                geometry.DictHalfEdges.Add(h4.Handle, h4);
                geometry.DictHalfEdges.Add(h1.Handle, h1);
                geometry.DictHalfEdges.Add(h2n.Handle, h2n);

                allH2NEdges.Add(h2n);

                next = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
            } while (start != next);

            start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            next  = start;
            do
            {
                var newFace = new Face(geometry.CreateFaceHandleId());

                var twinEdge = geometry.GetHalfEdgeByHandle(next.TwinHalfEdge);

                var h1 = geometry.GetHalfEdgeByHandle(twinEdge.TwinHalfEdge);
                var h2 = allH2NEdges.First(n => n.OriginVertex == twinEdge.OriginVertex);
                var h3 = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var h4 = geometry.GetHalfEdgeByHandle(h1.PrevHalfEdge);

                //set Face
                h1.IncidentFace = newFace.Handle;
                h2.IncidentFace = newFace.Handle;
                h3.IncidentFace = newFace.Handle;
                h4.IncidentFace = newFace.Handle;

                h1.NextHalfEdge = h2.Handle;
                h2.NextHalfEdge = h3.Handle;
                h3.NextHalfEdge = h4.Handle;
                h4.NextHalfEdge = h1.Handle;

                h1.PrevHalfEdge = h4.Handle;
                h2.PrevHalfEdge = h1.Handle;
                h3.PrevHalfEdge = h2.Handle;
                h4.PrevHalfEdge = h3.Handle;

                h3.TwinHalfEdge       = next.Handle;
                h3.OriginVertex       = geometry.GetHalfEdgeByHandle(next.NextHalfEdge).OriginVertex;
                next.TwinHalfEdge     = h3.Handle;
                newFace.OuterHalfEdge = h1.Handle;

                //write all changes
                geometry.ReplaceHalfEdge(h1);
                geometry.ReplaceHalfEdge(h2);
                geometry.ReplaceHalfEdge(h4);
                geometry.ReplaceHalfEdge(next);

                geometry.DictHalfEdges.Add(h3.Handle, h3);
                geometry.DictFaces.Add(newFace.Handle, newFace);

                newFace.FaceData.FaceNormal = GeometricOperations.CalculateFaceNormal(geometry.GetFaceVertices(newFace.Handle).ToList());

                geometry.ReplaceFace(newFace);

                next = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
            } while (start != next);

            return(geometry);
        }
예제 #6
0
        /// <summary>
        /// Insets a Face with a given offset. The new, center Face has the same Handle as the original Face.
        /// </summary>
        /// <param name="geometry">The geometry on which to perform a face inset.</param>
        /// <param name="faceHandle">The Handle of the face, the new one will be inseted to.</param>
        /// <param name="insetOffset">The offset of the inset in percent. Use values between 0 and 1. A value of 0.5f means 50% of the original face remains.</param>
        /// <returns>Returns the geometry with edited faces.</returns>
        public static Geometry InsetFace(this Geometry geometry, int faceHandle, float insetOffset)
        {
            if (insetOffset >= 1)
            {
                throw new ArgumentException("insetOffset can not be greate or equal to 1.");
            }
            if (insetOffset <= 0)
            {
                throw new ArgumentException("insetOffset can not be smaller or equal to 0.");
            }

            var face            = geometry.GetFaceByHandle(faceHandle);
            var allFaceVertices = geometry.GetFaceVertices(faceHandle).ToList();
            var meanPos         = GeometricOperations.GetVerticesMeanPos(allFaceVertices);

            //Dict sotres countEdges; [0] = edge1.handle, [1] = edge2twin.handle, [2] = edge3.handle, [3] = vertex.Handle
            var edgeStorage = new Dictionary <int, int[]>();

            var countEdges = 0;

            var start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            var next  = start;

            do
            {
                var nextEdge      = next.NextHalfEdge;
                var currentVertex = geometry.GetVertexByHandle(next.OriginVertex);

                var currentPos = currentVertex.VertData.Pos;
                var newPos     = (currentPos - meanPos) * insetOffset + meanPos;

                var newVertex = new Vertex(geometry.CreateVertHandleId(), newPos);
                var nextNext  = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
                var edge1     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge2Twin = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge2     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge3     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var newFace   = new Face(geometry.CreateFaceHandleId());

                //store info
                edgeStorage.Add(countEdges, new[] { edge1.Handle, edge2Twin.Handle, edge3.Handle, newVertex.Handle });

                newVertex.IncidentHalfEdge = edge3.Handle;
                newFace.OuterHalfEdge      = edge1.Handle;
                edge1.OriginVertex         = nextNext.OriginVertex;
                edge3.OriginVertex         = newVertex.Handle;
                edge2Twin.OriginVertex     = newVertex.Handle;
                //twins
                edge2.TwinHalfEdge     = edge2Twin.Handle;
                edge2Twin.TwinHalfEdge = edge2.Handle;
                //nexts
                edge1.NextHalfEdge = edge2.Handle;
                edge2.NextHalfEdge = edge3.Handle;
                edge3.NextHalfEdge = next.Handle;
                next.NextHalfEdge  = edge1.Handle;
                //prevs
                edge1.PrevHalfEdge = next.Handle;
                edge2.PrevHalfEdge = edge1.Handle;
                edge3.PrevHalfEdge = edge2.Handle;
                next.PrevHalfEdge  = edge3.Handle;
                //face
                edge1.IncidentFace          = newFace.Handle;
                edge2.IncidentFace          = newFace.Handle;
                edge3.IncidentFace          = newFace.Handle;
                next.IncidentFace           = newFace.Handle;
                edge2Twin.IncidentFace      = face.Handle;
                newFace.FaceData.FaceNormal = face.FaceData.FaceNormal;

                //write changes
                geometry.DictVertices.Add(newVertex.Handle, newVertex);
                geometry.DictFaces.Add(newFace.Handle, newFace);
                geometry.DictHalfEdges.Add(edge1.Handle, edge1);
                geometry.DictHalfEdges.Add(edge2Twin.Handle, edge2Twin);
                geometry.DictHalfEdges.Add(edge2.Handle, edge2);
                geometry.DictHalfEdges.Add(edge3.Handle, edge3);
                geometry.ReplaceHalfEdge(next);

                countEdges++;
                next = geometry.GetHalfEdgeByHandle(nextEdge);
            } while (start != next);

            for (var i = 0; i < countEdges; i++)
            {
                var prevFace = i - 1;
                var nextFace = i + 1;

                var faceData = edgeStorage[i];

                if (i == 0)
                {
                    prevFace = countEdges - 1;
                }
                if (i == countEdges - 1)
                {
                    nextFace           = 0;
                    face.OuterHalfEdge = faceData[1];
                    geometry.ReplaceFace(face);
                }

                var prevFaceData = edgeStorage[prevFace];
                var nextFaceData = edgeStorage[nextFace];

                var edge2Twin = geometry.GetHalfEdgeByHandle(faceData[1]);
                var edge3     = geometry.GetHalfEdgeByHandle(faceData[2]);
                var edge3Twin = geometry.GetHalfEdgeByHandle(prevFaceData[0]);
                var edge2     = geometry.GetHalfEdgeByHandle(edge2Twin.TwinHalfEdge);

                edge2Twin.PrevHalfEdge = prevFaceData[1];
                edge2Twin.NextHalfEdge = nextFaceData[1];
                edge2.OriginVertex     = nextFaceData[3];
                edge3Twin.TwinHalfEdge = edge3.Handle;
                edge3.TwinHalfEdge     = edge3Twin.Handle;

                //write
                geometry.ReplaceHalfEdge(edge2Twin);
                geometry.ReplaceHalfEdge(edge2);
                geometry.ReplaceHalfEdge(edge3Twin);
                geometry.ReplaceHalfEdge(edge3);
            }

            return(geometry);
        }
예제 #7
0
        /// <summary>
        /// Performs a Catmull-Clark Subdivision-Surface algorithm on a given geometry which is stored as DCEL.
        /// </summary>
        /// <param name="geometry">The geometry to perform the SD on.</param>
        /// <returns>A smoother geometry with </returns>
        public static Geometry CatmullClarkSubdivision(Geometry geometry)
        {
            //initializing
            var newGeometry = geometry.CloneGeometry();

            //computes all Face Vertices and all Edge Vertices
            var allFaceVertices = GetFaceVertices(geometry);
            var allEdgeVertices = GetEdgeVertices(geometry, allFaceVertices);

            //Calculates the new position of existing Vertices
            var allVertices = newGeometry.GetAllVertices().ToList();

            foreach (var vertex in allVertices)
            {
                var outgoingEdges = newGeometry.GetVertexStartingHalfEdges(vertex.Handle).ToList();

                //Get average of all face Points and average of all edge Points
                var faceVertices = new List <Vertex>();
                var edgeVertices = new List <Vertex>();
                foreach (var edge in outgoingEdges)
                {
                    var twin = geometry.GetHalfEdgeByHandle(edge.TwinHalfEdge);

                    if (allFaceVertices.ContainsKey(edge.IncidentFace))
                    {
                        faceVertices.Add(allFaceVertices[edge.IncidentFace]);
                    }
                    else
                    {
                        faceVertices.Add(allFaceVertices[twin.IncidentFace]);
                    }

                    if (allEdgeVertices.ContainsKey(edge.Handle))
                    {
                        edgeVertices.Add(allEdgeVertices[edge.Handle]);
                    }
                    else
                    {
                        edgeVertices.Add(allEdgeVertices[twin.Handle]);
                    }
                }

                var meanEdgeVertexPos = GeometricOperations.GetVerticesMeanPos(edgeVertices);
                var meanFaceVertexPos = GeometricOperations.GetVerticesMeanPos(faceVertices);

                float edgeCount = outgoingEdges.Count;

                var newVertexPos = (meanFaceVertexPos + 2 * meanEdgeVertexPos + (edgeCount - 3) * vertex.VertData.Pos) / edgeCount;
                var newVertex    = new Vertex(vertex.Handle, newVertexPos)
                {
                    IncidentHalfEdge = vertex.IncidentHalfEdge
                };

                newGeometry.ReplaceVertex(newVertex);
            }

            //adds newly calculated Edge Vertices
            var allEdges = geometry.GetAllHalfEdges();
            var doneHe   = new int[allEdges.Count() + 1];

            foreach (var edge in allEdges)
            {
                if (doneHe[edge.Handle] == edge.TwinHalfEdge)
                {
                    continue;
                }
                var vertexOld1 = edge.OriginVertex;

                var twinEdge = geometry.GetHalfEdgeByHandle(edge.TwinHalfEdge);

                var vertexOld2 = twinEdge.OriginVertex;

                //find correct Edge Vertex
                Vertex edgeVertex;
                if (allEdgeVertices.ContainsKey(edge.Handle))
                {
                    edgeVertex = allEdgeVertices[edge.Handle];
                }
                else
                {
                    edgeVertex = allEdgeVertices[twinEdge.Handle];
                }

                newGeometry.InsertVertex(vertexOld1, vertexOld2, edgeVertex.VertData.Pos);
                doneHe[edge.TwinHalfEdge] = edge.Handle;
            }

            newGeometry.SetHighestHandles();
            geometry = newGeometry.CloneGeometry();

            //creates the new quad faces and connects everything
            AddFaceVerticesAndNewFaces(geometry, newGeometry, allFaceVertices);

            return(newGeometry);
        }