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);
        }
Example #2
0
        private static void Join2DGeometries(Geometry first, Geometry second)
        {
            var highestVertHandle     = first.HighestVertHandle;
            var highestHalfEdgeHandle = first.HighestHalfEdgeHandle;
            var highestFaceHandle     = first.HighestFaceHandle;

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

            foreach (var v in second.DictVertices)
            {
                var vert = new Vertex(v.Value.Handle + highestVertHandle, v.Value.VertData.Pos);
                vert.IncidentHalfEdge = v.Value.IncidentHalfEdge + highestHalfEdgeHandle;

                vertDictHelper.Add(vert.Handle, vert);
            }
            second.DictVertices.Clear();
            second.DictVertices = vertDictHelper;

            var faceDictHelper = new Dictionary <int, Face>();

            foreach (var f in second.DictFaces)
            {
                var face = new Face(f.Value.Handle + highestFaceHandle, f.Value);

                if (face.OuterHalfEdge != default(int))
                {
                    var outerHeId = face.OuterHalfEdge + first.HighestHalfEdgeHandle;
                    face.OuterHalfEdge = outerHeId;
                }

                for (var k = 0; k < face.InnerHalfEdges.Count; k++)
                {
                    var innerHe = face.InnerHalfEdges[k];
                    innerHe = innerHe + first.HighestHalfEdgeHandle;
                    face.InnerHalfEdges[k] = innerHe;
                }

                faceDictHelper.Add(face.Handle, face);
            }
            second.DictFaces.Clear();
            second.DictFaces = faceDictHelper;

            var heDictHelper = new Dictionary <int, HalfEdge>();

            foreach (var he in second.DictHalfEdges)
            {
                var halfEdge = new HalfEdge(he.Value.Handle + highestHalfEdgeHandle, he.Value);

                halfEdge.IncidentFace = halfEdge.IncidentFace + first.HighestFaceHandle;
                halfEdge.OriginVertex = halfEdge.OriginVertex + first.HighestVertHandle;

                halfEdge.NextHalfEdge = halfEdge.NextHalfEdge + highestHalfEdgeHandle;
                halfEdge.PrevHalfEdge = halfEdge.PrevHalfEdge + highestHalfEdgeHandle;

                if (halfEdge.TwinHalfEdge != default(int))
                {
                    halfEdge.TwinHalfEdge = halfEdge.TwinHalfEdge + highestHalfEdgeHandle;
                }

                heDictHelper.Add(halfEdge.Handle, halfEdge);
            }
            second.DictHalfEdges.Clear();
            second.DictHalfEdges = heDictHelper;

            //Change winding.
            var hEdgesWChangedWinding = second.GetHalfEdgesWChangedWinding(second.GetAllHalfEdges()).ToList();

            //Add data of second geometry to the first.
            foreach (var vert in second.DictVertices)
            {
                first.DictVertices.Add(vert.Key, vert.Value);
            }

            foreach (var halfEdge in hEdgesWChangedWinding)
            {
                first.DictHalfEdges.Add(halfEdge.Handle, halfEdge);
            }

            //Write content of second unbounded face into the first - delete second unbounded face
            var firstUnbounded = first.DictFaces[first.DictFaces.Keys.Min()];
            var secUnbounded   = second.DictFaces[second.DictFaces.Keys.Min()];

            firstUnbounded.InnerHalfEdges.AddRange(secUnbounded.InnerHalfEdges);
            second.DictFaces.Remove(secUnbounded.Handle);

            var secUnboundedHalfEdges = new List <HalfEdge>();

            foreach (var he in first.GetAllHalfEdges())
            {
                if (he.IncidentFace == secUnbounded.Handle)
                {
                    secUnboundedHalfEdges.Add(he);
                }
            }

            //Replace the incident face of the half edges.
            foreach (var he in secUnboundedHalfEdges)
            {
                var halfEdge = he;
                halfEdge.IncidentFace = firstUnbounded.Handle;
                first.DictHalfEdges.Remove(halfEdge.Handle);
                first.DictHalfEdges.Add(halfEdge.Handle, halfEdge);
            }

            //Add faces to the first geometry and recalculate the face normals.
            foreach (var face in second.DictFaces)
            {
                first.DictFaces.Add(face.Key, face.Value);
                first.SetFaceNormal(first.GetFaceOuterVertices(face.Key).ToList(), first.DictFaces[face.Key]);
            }

            first.SetHighestHandles();
        }
        /// <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);
        }