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); }
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); }