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 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> /// Extrudes a given Face by a given offset along its normal vector. /// </summary> /// <param name="geometry">The geometry.</param> /// <param name="faceHandle">The handle of the face to extrude.</param> /// <param name="offset">How far the face should get extruded.</param> /// <returns></returns> public static Geometry ExtrudeFace(this Geometry geometry, int faceHandle, float offset) { var face = geometry.GetFaceByHandle(faceHandle); return(ExtrudeFaceByHandle(geometry, faceHandle, offset, face.FaceData.FaceNormal)); }
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); }
private static IEnumerable <BoundaryEdge> CreateHalfEdgesForBoundary(PolyBoundary outline) { var outlineVerts = OutlineVertices(outline); var boundaryEdges = BoundaryEdges(outlineVerts, outline); SetPrevAndNextForBoundary(boundaryEdges); var halfEdgesToUpdate = new List <HalfEdge>(); for (var i = boundaryEdges.Count - 1; i > -1; i--) { var bEdge = boundaryEdges[i]; if (!bEdge.IsOriginOldVert) { continue; //A half-edge can only exist if its source vertex is an old one. } int existingHeHandle; if (!IsEdgeExisting(bEdge.HalfEdge, boundaryEdges, out existingHeHandle)) { continue; //Check the target vertex to identify the existing half edge. } //If the existing half edge is halfedge.IncidentFace.OuterHalfEdge, replace it. var face = _geometry.GetFaceByHandle(bEdge.HalfEdge.IncidentFace); if (face.OuterHalfEdge == bEdge.HalfEdge.Handle) { face.OuterHalfEdge = existingHeHandle; _geometry.ReplaceFace(face); } //If the existing half edge is one of the unbounded faces inner half edges, replace it. var unboundedFace = _geometry.DictFaces[1]; for (var k = 0; k < unboundedFace.InnerHalfEdges.Count; k++) { var heHandle = unboundedFace.InnerHalfEdges[k]; if (heHandle != existingHeHandle) { continue; } var nextHe = _geometry.GetHalfEdgeByHandle(heHandle).NextHalfEdge; unboundedFace.InnerHalfEdges[k] = nextHe; _geometry.DictFaces[1] = unboundedFace; break; } var existingHe = _geometry.GetHalfEdgeByHandle(existingHeHandle); existingHe.NextHalfEdge = bEdge.HalfEdge.NextHalfEdge; existingHe.PrevHalfEdge = bEdge.HalfEdge.PrevHalfEdge; existingHe.IncidentFace = bEdge.HalfEdge.IncidentFace; halfEdgesToUpdate.Add(existingHe); SetPrevAndNextToExistingHalfEdge(bEdge, existingHeHandle, boundaryEdges, halfEdgesToUpdate); boundaryEdges.RemoveAt(i); } if (halfEdgesToUpdate.Count == 0) { return(boundaryEdges); } foreach (var he in halfEdgesToUpdate) { _geometry.ReplaceHalfEdge(he); } return(boundaryEdges); }
/// <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); }