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); }
private static void CreateSidefaces(Geometry geometry) { var unboundedFace = geometry.GetFaceByHandle(1); //The unbounded face is always added first - therefore it will always have 1 as handle. var frontLoopsStartHalfEdges = unboundedFace.InnerHalfEdges.Take(unboundedFace.InnerHalfEdges.Count / 2).ToList(); var backLoopsStartHalfEdges = unboundedFace.InnerHalfEdges.Skip(unboundedFace.InnerHalfEdges.Count / 2).ToList(); for (var i = 0; i < frontLoopsStartHalfEdges.Count; i++) { var frontEdgeLoop = geometry.GetHalfEdgeLoop(frontLoopsStartHalfEdges[i]).ToList(); var backEdgeLoop = geometry.GetHalfEdgeLoopReverse(backLoopsStartHalfEdges[i]).ToList(); var newHalfEdges = new List <HalfEdge>(); var newFaces = new List <Face>(); for (var j = 0; j < frontEdgeLoop.Count; j++) { var halfEdgeFront = frontEdgeLoop[j]; var halfEdgeInBack = backEdgeLoop[j]; var backOriginVert = geometry.GetHalfEdgeByHandle(halfEdgeInBack.NextHalfEdge).OriginVertex; var frontOriginVert = geometry.GetHalfEdgeByHandle(halfEdgeFront.NextHalfEdge).OriginVertex; var newFromBack = new HalfEdge(geometry.CreateHalfEdgeHandleId()) { OriginVertex = backOriginVert, NextHalfEdge = halfEdgeFront.Handle, PrevHalfEdge = halfEdgeInBack.Handle }; var newFace = new Face(geometry.CreateFaceHandleId(), newFromBack.Handle); newFaces.Add(newFace); geometry.DictFaces.Add(newFace.Handle, newFace); newFromBack.IncidentFace = newFace.Handle; var newFromFront = new HalfEdge(geometry.CreateHalfEdgeHandleId()) { OriginVertex = frontOriginVert, NextHalfEdge = halfEdgeInBack.Handle, PrevHalfEdge = halfEdgeFront.Handle, IncidentFace = newFace.Handle }; halfEdgeFront.IncidentFace = newFace.Handle; halfEdgeFront.NextHalfEdge = newFromFront.Handle; halfEdgeFront.PrevHalfEdge = newFromBack.Handle; halfEdgeInBack.IncidentFace = newFace.Handle; halfEdgeInBack.NextHalfEdge = newFromBack.Handle; halfEdgeInBack.PrevHalfEdge = newFromFront.Handle; geometry.ReplaceHalfEdge(halfEdgeFront); geometry.ReplaceHalfEdge(halfEdgeInBack); newHalfEdges.Add(newFromBack); newHalfEdges.Add(newFromFront); } for (var j = 0; j < newHalfEdges.Count; j++) { var current = newHalfEdges[j]; if (j == 0) { current.TwinHalfEdge = newHalfEdges.Last().Handle; } else if (j == newHalfEdges.Count - 1) { current.TwinHalfEdge = newHalfEdges[0].Handle; } else if (j % 2 != 0 && j != newHalfEdges.Count - 1) //odd { current.TwinHalfEdge = newHalfEdges[j + 1].Handle; } else if (j % 2 == 0 && j != 0) //even { current.TwinHalfEdge = newHalfEdges[j - 1].Handle; } newHalfEdges[j] = current; geometry.DictHalfEdges.Add(current.Handle, current); } foreach (var face in newFaces) { geometry.SetFaceNormal(geometry.GetFaceOuterVertices(face.Handle).ToList(), geometry.DictFaces[face.Handle]); } } //Delete unbounded face geometry.DictFaces.Remove(unboundedFace.Handle); }
/// <summary> /// Inserts a new Vertex between two given exsisting Vertices. /// </summary> /// <param name="geometry">The Geometry to insert a Vertex.</param> /// <param name="p">Handle of Vertex one.</param> /// <param name="q">Handle of Vertex two.</param> /// <param name="pos">Position of the new Vertex</param> /// <returns>New Vertex Handle.</returns> public static int InsertVertex(this Geometry geometry, int p, int q, float3 pos) { var adjacentVertices = geometry.GetVertexAdjacentVertices(p).ToList(); for (var i = 0; i < adjacentVertices.Count; i++) { if (adjacentVertices[i].Handle == q) { break; } if (i == adjacentVertices.Count - 1) { throw new ArgumentException("Vertices with Handle q=" + q + " and p=" + p + " are not adjacent!"); } } var newVertex = new Vertex(geometry.CreateVertHandleId(), pos); //add two new Half Edges var newHalfEdge1 = new HalfEdge(geometry.CreateHalfEdgeHandleId()); var newHalfEdge2 = new HalfEdge(geometry.CreateHalfEdgeHandleId()); //set origin to new Vertex newHalfEdge1.OriginVertex = newVertex.Handle; newHalfEdge2.OriginVertex = newVertex.Handle; newVertex.IncidentHalfEdge = newHalfEdge2.Handle; var vertexP = geometry.GetVertexByHandle(p); var vertexQ = geometry.GetVertexByHandle(q); //Find Half Edge between p and q var incomingEdges = geometry.GetVertexStartingHalfEdges(vertexP.Handle); var he1 = new HalfEdge(); var he2 = new HalfEdge(); foreach (var halfEdge in incomingEdges) { var twinEdge = geometry.GetHalfEdgeByHandle(halfEdge.TwinHalfEdge); if (twinEdge.OriginVertex != vertexQ.Handle) { continue; } he1 = halfEdge; he2 = twinEdge; } var next1 = geometry.GetHalfEdgeByHandle(he2.NextHalfEdge); var next2 = geometry.GetHalfEdgeByHandle(he1.NextHalfEdge); //change Handels he1.TwinHalfEdge = newHalfEdge1.Handle; newHalfEdge1.TwinHalfEdge = he1.Handle; newHalfEdge1.NextHalfEdge = he2.NextHalfEdge; he2.NextHalfEdge = newHalfEdge1.Handle; newHalfEdge1.PrevHalfEdge = he2.Handle; next1.PrevHalfEdge = newHalfEdge1.Handle; he2.TwinHalfEdge = newHalfEdge2.Handle; newHalfEdge2.TwinHalfEdge = he2.Handle; newHalfEdge2.NextHalfEdge = he1.NextHalfEdge; he1.NextHalfEdge = newHalfEdge2.Handle; newHalfEdge2.PrevHalfEdge = he1.Handle; next2.PrevHalfEdge = newHalfEdge2.Handle; //reconnect faces newHalfEdge1.IncidentFace = he2.IncidentFace; newHalfEdge2.IncidentFace = he1.IncidentFace; //replace exsisnting Edges geometry.ReplaceHalfEdge(he1); geometry.ReplaceHalfEdge(he2); geometry.ReplaceHalfEdge(next1); geometry.ReplaceHalfEdge(next2); //add to dict geometry.DictVertices.Add(newVertex.Handle, newVertex); geometry.DictHalfEdges.Add(newHalfEdge1.Handle, newHalfEdge1); geometry.DictHalfEdges.Add(newHalfEdge2.Handle, newHalfEdge2); return(newVertex.Handle); }
/// <summary> /// Inserts a pair of HalfEdges between two (non adjacent) vertices of a Face. /// </summary> /// <param name="geometry">The Geometry to insert a dignonal</param> /// <param name="p">First Vertex handle.</param> /// <param name="q">Second Vertex handle.</param> /// <exception cref="Exception"></exception> public static void InsertDiagonal(this Geometry geometry, int p, int q) { var pStartHe = new HalfEdge(); var qStartHe = new HalfEdge(); var face = geometry.GetFaceToInsertDiag(p, q, ref pStartHe, ref qStartHe); if (geometry.IsVertexAdjacentToVertex(p, q, pStartHe, qStartHe)) { throw new ArgumentException("A diagonal can't be inserted between adjacent Vertices!"); } var newFromP = new HalfEdge(geometry.CreateHalfEdgeHandleId()); var newFromQ = new HalfEdge(geometry.CreateHalfEdgeHandleId()); newFromP.OriginVertex = p; newFromP.NextHalfEdge = qStartHe.Handle; newFromP.PrevHalfEdge = pStartHe.PrevHalfEdge; newFromP.IncidentFace = face.Handle; newFromQ.OriginVertex = q; newFromQ.NextHalfEdge = pStartHe.Handle; newFromQ.PrevHalfEdge = qStartHe.PrevHalfEdge; newFromQ.IncidentFace = face.Handle; newFromP.TwinHalfEdge = newFromQ.Handle; newFromQ.TwinHalfEdge = newFromP.Handle; geometry.DictHalfEdges.Add(newFromP.Handle, newFromP); geometry.DictHalfEdges.Add(newFromQ.Handle, newFromQ); //Assign new sucessor to previous HalfEdges from p and q & assign new predecessor for qStartHe and pStartHe. var prevHeP = geometry.GetHalfEdgeByHandle(pStartHe.PrevHalfEdge); var prevHeQ = geometry.GetHalfEdgeByHandle(qStartHe.PrevHalfEdge); var prevHePUpdate = geometry.DictHalfEdges[prevHeP.Handle]; prevHePUpdate.NextHalfEdge = newFromP.Handle; geometry.DictHalfEdges[prevHeP.Handle] = prevHePUpdate; var prevHeQUpdate = geometry.DictHalfEdges[prevHeQ.Handle]; prevHeQUpdate.NextHalfEdge = newFromQ.Handle; geometry.DictHalfEdges[prevHeQ.Handle] = prevHeQUpdate; var nextHePUpdate = geometry.DictHalfEdges[pStartHe.Handle]; nextHePUpdate.PrevHalfEdge = newFromQ.Handle; geometry.DictHalfEdges[pStartHe.Handle] = nextHePUpdate; var nextHeQUpdate = geometry.DictHalfEdges[qStartHe.Handle]; nextHeQUpdate.PrevHalfEdge = newFromP.Handle; geometry.DictHalfEdges[qStartHe.Handle] = nextHeQUpdate; var holes = geometry.GetHoles(face); if (holes.Count != 0 && IsNewEdgeToHole(holes, p, q, face)) { return; } var newFace = new Face(geometry.CreateFaceHandleId(), newFromQ.Handle); //The face normal of the newFace equals the normal of the original Face because adding a diagonal does not change the face vertices position. var newFaceData = newFace.FaceData; newFaceData.FaceNormal = face.FaceData.FaceNormal; newFace.FaceData = newFaceData; geometry.DictFaces.Add(newFace.Handle, newFace); //Assign the handle of the new Face to its HalfEdges. geometry.AssignFaceHandle(newFace.OuterHalfEdge, newFace); //Set Face.OuterHalfEdge to newFromP - old OuterHalfEdge can be part of new Face now! var currentFace = face; currentFace.OuterHalfEdge = newFromP.Handle; face = currentFace; geometry.DictFaces[face.Handle] = face; }
private static void AddFaceVerticesAndNewFaces(Geometry geometry, Geometry newGeometry, Dictionary <int, Vertex> allFaceVertices) { var allFaces = geometry.GetAllFaces(); foreach (var face in allFaces) { Vertex faceVertex = new Vertex(newGeometry.CreateVertHandleId(), allFaceVertices[face.Handle].VertData.Pos); HalfEdge startEdge = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge); HalfEdge nextEdge = startEdge; //stores Halfedges without Twin Dictionary <int, HalfEdge> halfEdges2 = new Dictionary <int, HalfEdge>(); Dictionary <int, HalfEdge> halfEdges1 = new Dictionary <int, HalfEdge>(); newGeometry.DictVertices.Add(faceVertex.Handle, faceVertex); int i = 0; do { HalfEdge h1 = new HalfEdge(newGeometry.CreateHalfEdgeHandleId()); HalfEdge h2 = new HalfEdge(newGeometry.CreateHalfEdgeHandleId()); HalfEdge h3 = newGeometry.GetHalfEdgeByHandle(nextEdge.PrevHalfEdge); HalfEdge h4 = newGeometry.GetHalfEdgeByHandle(nextEdge.Handle); //create new quad face Face newFace; newFace = i == 0 ? face : new Face(newGeometry.CreateFaceHandleId()); nextEdge = geometry.GetHalfEdgeByHandle(nextEdge.NextHalfEdge); 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; h1.OriginVertex = nextEdge.OriginVertex; h2.OriginVertex = faceVertex.Handle; h1.IncidentFace = newFace.Handle; h2.IncidentFace = newFace.Handle; h3.IncidentFace = newFace.Handle; h4.IncidentFace = newFace.Handle; faceVertex.IncidentHalfEdge = h2.Handle; newFace.OuterHalfEdge = h1.Handle; //add and replace changed newGeometry.DictHalfEdges.Add(h1.Handle, h1); newGeometry.DictHalfEdges.Add(h2.Handle, h2); newGeometry.ReplaceHalfEdge(h3); newGeometry.ReplaceHalfEdge(h4); newGeometry.ReplaceVertex(faceVertex); if (i == 0) // the old face becomes the first quad, so no new face to create { newGeometry.ReplaceFace(newFace); } else //create new face { newGeometry.DictFaces.Add(newFace.Handle, newFace); } //Stores Vertices to get the face normal List <Vertex> faceVertices = new List <Vertex> { newGeometry.GetVertexByHandle(h1.OriginVertex), newGeometry.GetVertexByHandle(h2.OriginVertex), newGeometry.GetVertexByHandle(h3.OriginVertex), newGeometry.GetVertexByHandle(h4.OriginVertex) }; newGeometry.SetFaceNormal(faceVertices, newFace); halfEdges2.Add(i, h2); halfEdges1.Add(i, h1); //for the second Edge per Face connect the twin if (i > 0) { HalfEdge h1N = halfEdges1[i - 1]; h1N.TwinHalfEdge = halfEdges2[i].Handle; HalfEdge h2N = halfEdges2[i]; h2N.TwinHalfEdge = h1N.Handle; newGeometry.ReplaceHalfEdge(h1N); newGeometry.ReplaceHalfEdge(h2N); } i++; nextEdge = geometry.GetHalfEdgeByHandle(nextEdge.NextHalfEdge); } while (startEdge != nextEdge); //set Twin of firsts and lasts of each new Face var h2Firts = halfEdges2[0]; var h1Last = halfEdges1[i - 1]; h2Firts.TwinHalfEdge = h1Last.Handle; h1Last.TwinHalfEdge = h2Firts.Handle; newGeometry.ReplaceHalfEdge(h2Firts); newGeometry.ReplaceHalfEdge(h1Last); } }
/// <summary> /// Creates and returns a UV-Sphere as a DCEL with the specified dimensions centered in the worlds coordinate system. /// </summary> /// <param name="radius">Radius of the sphere.</param> /// <param name="horizontalResolution">Lines of latitude, smallest value is 3.</param> /// <param name="verticalResolution">Lines of longitude, smallest value is 3.</param> /// <returns>A UV-Sphere centered in the world coordinate system as a DCEL.</returns> public static Geometry CreateSpehreGeometry(float radius, int horizontalResolution, int verticalResolution) { //check input if (radius <= 0) { throw new ArgumentException("Radius can not be <= 0"); } if (horizontalResolution <= 3) { horizontalResolution = 3; } if (verticalResolution <= 2) { verticalResolution = 2; } var sphere = new Geometry(); var northPole = new Vertex(sphere.CreateVertHandleId(), new float3(0, radius, 0)); var southPole = new Vertex(sphere.CreateVertHandleId(), new float3(0, -radius, 0)); var horizontalAngleStep = System.Math.PI * 2 / horizontalResolution; // s var verrticalAngleStep = System.Math.PI / verticalResolution; // t var currentLatitudeVerticesHandles = new int[horizontalResolution]; var lastlatitudeVerticesHandles = new int[horizontalResolution]; //stores last vertices to connect them later with the next latitude vertices for (var i = 1; i < verticalResolution + 1; i++) { //create all vertices if (i < verticalResolution) { for (var j = 0; j < horizontalResolution; j++) { //create all Vertices of current latitude var xPos = (float)(radius * System.Math.Sin(horizontalAngleStep * j) * System.Math.Sin(verrticalAngleStep * i)); var yPos = (float)(radius * System.Math.Cos(verrticalAngleStep * (i))); var zPos = (float)(radius * System.Math.Cos(horizontalAngleStep * j) * System.Math.Sin(verrticalAngleStep * i)); var circleVertex = new Vertex(sphere.CreateVertHandleId(), new float3(xPos, yPos, zPos)); sphere.DictVertices.Add(circleVertex.Handle, circleVertex); currentLatitudeVerticesHandles[j] = circleVertex.Handle; } } //create faces var topHeHandles = new int[horizontalResolution]; for (var j = 0; j < horizontalResolution; j++) { // bottom triangles of sphere if (i == verticalResolution) { var bottomTriangle = new Face(sphere.CreateFaceHandleId()); var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); topHeHandles[j] = h1.Handle; h1.NextHalfEdge = h2.Handle; h2.NextHalfEdge = h3.Handle; h3.NextHalfEdge = h1.Handle; h1.PrevHalfEdge = h3.Handle; h2.PrevHalfEdge = h1.Handle; h3.PrevHalfEdge = h2.Handle; h1.IncidentFace = bottomTriangle.Handle; h2.IncidentFace = bottomTriangle.Handle; h3.IncidentFace = bottomTriangle.Handle; h1.OriginVertex = currentLatitudeVerticesHandles[j]; h2.OriginVertex = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1]; h3.OriginVertex = southPole.Handle; bottomTriangle.OuterHalfEdge = h1.Handle; southPole.IncidentHalfEdge = h3.Handle; //write changes sphere.DictHalfEdges.Add(h1.Handle, h1); sphere.DictHalfEdges.Add(h2.Handle, h2); sphere.DictHalfEdges.Add(h3.Handle, h3); sphere.DictFaces.Add(bottomTriangle.Handle, bottomTriangle); } // top triangles of sphere else if (i == 1) { var topTriangle = new Face(sphere.CreateFaceHandleId()); var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); topHeHandles[j] = h1.Handle; h1.NextHalfEdge = h2.Handle; h2.NextHalfEdge = h3.Handle; h3.NextHalfEdge = h1.Handle; h1.PrevHalfEdge = h3.Handle; h2.PrevHalfEdge = h1.Handle; h3.PrevHalfEdge = h2.Handle; h1.IncidentFace = topTriangle.Handle; h2.IncidentFace = topTriangle.Handle; h3.IncidentFace = topTriangle.Handle; h1.OriginVertex = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1]; h2.OriginVertex = currentLatitudeVerticesHandles[j]; h3.OriginVertex = northPole.Handle; topTriangle.OuterHalfEdge = h1.Handle; var currentVertex = sphere.GetVertexByHandle(currentLatitudeVerticesHandles[j]); currentVertex.IncidentHalfEdge = h2.Handle; northPole.IncidentHalfEdge = h3.Handle; //write changes sphere.DictHalfEdges.Add(h1.Handle, h1); sphere.DictHalfEdges.Add(h2.Handle, h2); sphere.DictHalfEdges.Add(h3.Handle, h3); sphere.DictFaces.Add(topTriangle.Handle, topTriangle); sphere.ReplaceVertex(currentVertex); } // middle quads of sphere else { var quad = new Face(sphere.CreateFaceHandleId()); var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); var h4 = new HalfEdge(sphere.CreateHalfEdgeHandleId()); topHeHandles[j] = h1.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; h1.IncidentFace = quad.Handle; h2.IncidentFace = quad.Handle; h3.IncidentFace = quad.Handle; h4.IncidentFace = quad.Handle; quad.OuterHalfEdge = h1.Handle; h4.OriginVertex = currentLatitudeVerticesHandles[j]; h3.OriginVertex = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1]; h2.OriginVertex = j == horizontalResolution - 1 ? lastlatitudeVerticesHandles[0] : lastlatitudeVerticesHandles[j + 1]; h1.OriginVertex = lastlatitudeVerticesHandles[j]; var currentVertex = sphere.GetVertexByHandle(currentLatitudeVerticesHandles[j]); currentVertex.IncidentHalfEdge = h4.Handle; //write changes sphere.DictFaces.Add(quad.Handle, quad); sphere.DictHalfEdges.Add(h1.Handle, h1); sphere.DictHalfEdges.Add(h2.Handle, h2); sphere.DictHalfEdges.Add(h3.Handle, h3); sphere.DictHalfEdges.Add(h4.Handle, h4); sphere.ReplaceVertex(currentVertex); } } //set twins for (int j = 0; j < horizontalResolution; j++) { //set twins of adjacent triangles bottom if (i == 1) { int nextH1Index; nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1; var h1 = sphere.GetHalfEdgeByHandle(topHeHandles[j]); var h2 = sphere.GetHalfEdgeByHandle(h1.NextHalfEdge); var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]); var nextH3 = sphere.GetHalfEdgeByHandle(nextH1.PrevHalfEdge); nextH3.TwinHalfEdge = h2.Handle; h2.TwinHalfEdge = nextH3.Handle; sphere.ReplaceHalfEdge(nextH3); sphere.ReplaceHalfEdge(h2); } else if (i == verticalResolution) { int nextH1Index; nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1; var h1 = sphere.GetHalfEdgeByHandle(topHeHandles[j]); var h3 = sphere.GetHalfEdgeByHandle(h1.PrevHalfEdge); var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]); var nextH2 = sphere.GetHalfEdgeByHandle(nextH1.NextHalfEdge); nextH2.TwinHalfEdge = h3.Handle; h3.TwinHalfEdge = nextH2.Handle; sphere.ReplaceHalfEdge(nextH2); sphere.ReplaceHalfEdge(h3); } else //set twins of adjacent quads { var h1 = sphere.GetHalfEdgeByHandle(topHeHandles[j]); var h4 = sphere.GetHalfEdgeByHandle(h1.PrevHalfEdge); int nextH1Index; nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1; var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]); var nextH2 = sphere.GetHalfEdgeByHandle(nextH1.NextHalfEdge); nextH2.TwinHalfEdge = h4.Handle; h4.TwinHalfEdge = nextH2.Handle; sphere.ReplaceHalfEdge(nextH2); sphere.ReplaceHalfEdge(h4); } //set twin of face on top if (i > 1) { var h1 = sphere.GetHalfEdgeByHandle(topHeHandles[j]); var lastVertex = sphere.GetVertexByHandle(lastlatitudeVerticesHandles[j]); var topH1 = sphere.GetHalfEdgeByHandle(lastVertex.IncidentHalfEdge); while (true) { if (topH1.TwinHalfEdge == 0) { break; } topH1 = sphere.GetHalfEdgeByHandle(topH1.NextHalfEdge); } topH1.TwinHalfEdge = h1.Handle; h1.TwinHalfEdge = topH1.Handle; sphere.ReplaceHalfEdge(h1); sphere.ReplaceHalfEdge(topH1); } } Array.Copy(currentLatitudeVerticesHandles, lastlatitudeVerticesHandles, currentLatitudeVerticesHandles.Length); } sphere.DictVertices.Add(northPole.Handle, northPole); sphere.DictVertices.Add(southPole.Handle, southPole); //calculate normals var allFaces = sphere.GetAllFaces().ToList(); foreach (var face in allFaces) { sphere.SetFaceNormal(sphere.GetFaceVertices(face.Handle).ToList(), face); } return(sphere); }
/// <summary> /// Creates and returns a cone with the given dimensions. /// </summary> /// <param name="baseRadius">The radius of the base circle.</param> /// <param name="dimensionY">The height of the cone.</param> /// <param name="sliceCount">The horizontal resolution of the base circle. Min value is 3. For a basic cone 15.</param> /// <returns></returns> public static Geometry CreateConeGeometry(float baseRadius, float dimensionY, int sliceCount) { //check input if (sliceCount < 3) { sliceCount = 3; } if (baseRadius <= 0 || dimensionY <= 0) { throw new ArgumentException("You can not input parameters <= 0"); } var cone = new Geometry(); var northPole = new Vertex(cone.CreateVertHandleId(), new float3(0, dimensionY / 2, 0)); var southPole = new Vertex(cone.CreateVertHandleId(), new float3(0, -dimensionY / 2, 0)); var angleStep = System.Math.PI * 2 / sliceCount; var yPos = -dimensionY / 2.0f; int[] firstHandles = null; //stores the handles of the first slice to connect it later with the last slice var lastH3 = new HalfEdge(); var lastH2 = new HalfEdge(); var lastVertex = southPole; for (var i = 1; i < sliceCount + 1; i++) { var x = (float)System.Math.Cos(angleStep * i) * baseRadius; var z = (float)System.Math.Sin(angleStep * i) * baseRadius; var tempVertex = new Vertex(cone.CreateVertHandleId(), new float3(x, yPos, z)); //south to temp var h1 = new HalfEdge(cone.CreateHalfEdgeHandleId()); var h2 = new HalfEdge(cone.CreateHalfEdgeHandleId()); //twin of h1 tempVertex.IncidentHalfEdge = h2.Handle; h1.OriginVertex = southPole.Handle; h2.OriginVertex = tempVertex.Handle; h1.TwinHalfEdge = h2.Handle; h2.TwinHalfEdge = h1.Handle; //temp to north var h3 = new HalfEdge(cone.CreateHalfEdgeHandleId()); var h4 = new HalfEdge(cone.CreateHalfEdgeHandleId()); northPole.IncidentHalfEdge = h3.Handle; southPole.IncidentHalfEdge = h1.Handle; h3.OriginVertex = northPole.Handle; h4.OriginVertex = tempVertex.Handle; h3.TwinHalfEdge = h4.Handle; h4.TwinHalfEdge = h3.Handle; if (lastVertex == southPole) { firstHandles = new[] { tempVertex.Handle, h1.Handle, h4.Handle }; lastH3 = h3; lastH2 = h2; cone.DictVertices.Add(tempVertex.Handle, tempVertex); cone.DictHalfEdges.Add(h1.Handle, h1); cone.DictHalfEdges.Add(h2.Handle, h2); cone.DictHalfEdges.Add(h3.Handle, h3); cone.DictHalfEdges.Add(h4.Handle, h4); lastVertex = tempVertex; continue; } //temp to last var h5 = new HalfEdge(cone.CreateHalfEdgeHandleId()); var h6 = new HalfEdge(cone.CreateHalfEdgeHandleId()); h5.OriginVertex = lastVertex.Handle; h6.OriginVertex = tempVertex.Handle; h5.TwinHalfEdge = h6.Handle; h6.TwinHalfEdge = h5.Handle; //create top triangles south-temp-last var triangle1 = new Face(cone.CreateFaceHandleId()); h5.NextHalfEdge = h4.Handle; triangle1.OuterHalfEdge = h5.Handle; h4.NextHalfEdge = lastH3.Handle; lastH3.NextHalfEdge = h5.Handle; h5.IncidentFace = triangle1.Handle; h4.IncidentFace = triangle1.Handle; lastH3.IncidentFace = triangle1.Handle; h5.PrevHalfEdge = lastH3.Handle; lastH3.PrevHalfEdge = h4.Handle; h4.PrevHalfEdge = h5.Handle; //north-last-temp var triangle2 = new Face(cone.CreateFaceHandleId()); h6.NextHalfEdge = lastH2.Handle; triangle2.OuterHalfEdge = h6.Handle; lastH2.NextHalfEdge = h1.Handle; h1.NextHalfEdge = h6.Handle; h6.IncidentFace = triangle2.Handle; lastH2.IncidentFace = triangle2.Handle; h1.IncidentFace = triangle2.Handle; h6.PrevHalfEdge = h1.Handle; h1.PrevHalfEdge = lastH2.Handle; lastH2.PrevHalfEdge = h6.Handle; //write cone.DictVertices.Add(tempVertex.Handle, tempVertex); cone.DictHalfEdges.Add(h1.Handle, h1); cone.DictHalfEdges.Add(h2.Handle, h2); cone.DictHalfEdges.Add(h3.Handle, h3); cone.DictHalfEdges.Add(h4.Handle, h4); cone.DictHalfEdges.Add(h5.Handle, h5); cone.DictHalfEdges.Add(h6.Handle, h6); cone.ReplaceHalfEdge(lastH2); cone.ReplaceHalfEdge(lastH3); cone.DictFaces.Add(triangle1.Handle, triangle1); cone.DictFaces.Add(triangle2.Handle, triangle2); lastH2 = h2; lastH3 = h3; lastVertex = tempVertex; } //add south and north pole cone.DictVertices.Add(southPole.Handle, southPole); cone.DictVertices.Add(northPole.Handle, northPole); //create last 2 triangles var firstVertex = cone.GetVertexByHandle(firstHandles[0]); var firtstH1 = cone.GetHalfEdgeByHandle(firstHandles[1]); var firstH4 = cone.GetHalfEdgeByHandle(firstHandles[2]); var lastH5 = new HalfEdge(cone.CreateHalfEdgeHandleId()); var lastH6 = new HalfEdge(cone.CreateHalfEdgeHandleId()); lastH5.OriginVertex = lastVertex.Handle; lastH6.OriginVertex = firstVertex.Handle; lastH5.TwinHalfEdge = lastH6.Handle; lastH6.TwinHalfEdge = lastH5.Handle; //create to triangles south-temp-last, north-last-temp var triangleL1 = new Face(cone.CreateFaceHandleId()) { OuterHalfEdge = lastH5.Handle }; lastH5.NextHalfEdge = firstH4.Handle; firstH4.NextHalfEdge = lastH3.Handle; lastH3.NextHalfEdge = lastH5.Handle; lastH5.IncidentFace = triangleL1.Handle; firstH4.IncidentFace = triangleL1.Handle; lastH3.IncidentFace = triangleL1.Handle; lastH5.PrevHalfEdge = lastH3.Handle; lastH3.PrevHalfEdge = firstH4.Handle; firstH4.PrevHalfEdge = lastH5.Handle; var triangleL2 = new Face(cone.CreateFaceHandleId()) { OuterHalfEdge = lastH6.Handle }; lastH6.NextHalfEdge = lastH2.Handle; lastH2.NextHalfEdge = firtstH1.Handle; firtstH1.NextHalfEdge = lastH6.Handle; lastH6.IncidentFace = triangleL2.Handle; lastH2.IncidentFace = triangleL2.Handle; firtstH1.IncidentFace = triangleL2.Handle; lastH6.PrevHalfEdge = firtstH1.Handle; firtstH1.PrevHalfEdge = lastH2.Handle; lastH2.PrevHalfEdge = lastH6.Handle; //write cone.ReplaceHalfEdge(firtstH1); cone.DictHalfEdges.Add(lastH5.Handle, lastH5); cone.DictHalfEdges.Add(lastH6.Handle, lastH6); cone.ReplaceHalfEdge(lastH2); cone.ReplaceHalfEdge(lastH3); cone.ReplaceHalfEdge(firstH4); cone.DictFaces.Add(triangleL1.Handle, triangleL1); cone.DictFaces.Add(triangleL2.Handle, triangleL2); //face normals var allFaces = cone.GetAllFaces().ToList(); foreach (var face in allFaces) { cone.SetFaceNormal(cone.GetFaceVertices(face.Handle).ToList(), face); } return(cone); }