Пример #1
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);
        }
Пример #2
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);
        }
Пример #3
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);
        }
Пример #4
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);
        }