//Vertices need to be reduced to 2D //see Akenine-Möller, Tomas; Haines, Eric; Hoffman, Naty (2016): Real-Time Rendering, p. 754 /// <summary> /// Tests if a point/vertex lies inside or outside a face - Only use this if you know the face AND vertex lie in the same plane and this plane is parallel to xy or xz or yz! /// </summary> /// <param name="geometry">The geometry the polygon (here: face) belongs to.</param> /// <param name="face">The faces to be tested. It will not be Reduced2D!</param> /// <param name="v">The vertex to be tested.</param> /// <returns></returns> public static bool IsPointInPolygon(this Geometry geometry, Face face, float3 v) { var inside = false; var faceVerts = geometry.GetFaceVertices(face.Handle).ToList(); var v1 = geometry.GetVertexByHandle(faceVerts.Last().Handle); var v1Pos = geometry.Get2DVertPos(face, v1.Handle); var y0 = v1Pos.y >= v.y; foreach (var vert in faceVerts) { var e1Pos = geometry.Get2DVertPos(face, vert.Handle); var y1 = e1Pos.y >= v.y; if (y0 != y1) { if ((e1Pos.y - v.y) * (v1Pos.x - e1Pos.x) >= (e1Pos.x - v.x) * (v1Pos.y - e1Pos.y) == y1) { inside = !inside; } } y0 = y1; v1Pos = e1Pos; } return(inside); }
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 AssignFaceHandle(this Geometry geometry, int heHandle, Face newFace) { var oldFaceHandle = geometry.GetHalfEdgeByHandle(heHandle).IncidentFace; var currentHe = geometry.GetHalfEdgeByHandle(heHandle); do { currentHe.IncidentFace = newFace.Handle; geometry.DictHalfEdges[currentHe.Handle] = currentHe; currentHe = geometry.GetHalfEdgeByHandle(currentHe.NextHalfEdge); } while (currentHe.Handle != heHandle); //Assign newFace to possible holes in the "old" face. var oldFace = geometry.GetFaceByHandle(oldFaceHandle); if (oldFace.InnerHalfEdges.Count == 0) { return; } var inner = new List <int>(); inner.AddRange(oldFace.InnerHalfEdges); foreach (var heh in inner) { var origin = geometry.GetHalfEdgeByHandle(heh).OriginVertex; if (!geometry.IsPointInPolygon(newFace, geometry.GetVertexByHandle(origin))) { continue; } oldFace.InnerHalfEdges.Remove(heh); newFace.InnerHalfEdges.Add(heh); var curHe = geometry.GetHalfEdgeByHandle(heh); do { curHe.IncidentFace = newFace.Handle; geometry.DictHalfEdges[curHe.Handle] = curHe; curHe = geometry.GetHalfEdgeByHandle(curHe.NextHalfEdge); } while (curHe.Handle != heh); } }
private static IEnumerable <Vertex> GetLeftChain(IList <Vertex> sortedVerts, Face face) { var heHandle = new int(); var endOfChain = sortedVerts.Last(); var startingAtFirstV = _geometry.GetVertexStartingHalfEdges(sortedVerts[0].Handle).ToList(); if (startingAtFirstV.Count > 1) { foreach (var heh in startingAtFirstV) { var he = heh; if (he.IncidentFace == face.Handle) { heHandle = heh.Handle; } } } else { heHandle = sortedVerts[0].IncidentHalfEdge; } do { var halfEdge = _geometry.GetHalfEdgeByHandle(heHandle); yield return(_geometry.GetVertexByHandle(halfEdge.OriginVertex)); heHandle = halfEdge.NextHalfEdge; } while (_geometry.GetHalfEdgeByHandle(heHandle).OriginVertex != endOfChain.Handle); }
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> /// 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); }
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); }