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