public static int Pop(this IntSet self) { if (self.Count == 0) { throw new InvalidOperationException(); } int result = self.First(); self.Remove(result); return(result); }
/// <summary> /// Clips the mesh with the given plane. /// The part on the positive hals will remain. /// Will return null when everything is clipped. /// Cap-faces will be built on everything that is cut open by the plane (non-convex cap faces are not handled properly). /// Only works for meshes without Face-/FaceVertexAttributes -> attributes will be invalid for generated faces. /// </summary> public PolyMesh ClipByPlane(Plane3d plane, double epsilon = 1e-7) { var clippedMesh = SplitOnPlane(plane, epsilon).Item2; // in case everything is clipped away if (clippedMesh == null) { return(null); } // 1. go trough all edges // 2. if edge on plane -> test if there is an open face along the plane (border edges) var vertexOnPlane = clippedMesh.PositionArray.Map(clippedMesh.VertexCount, p => plane.Height(p).Abs() <= epsilon); clippedMesh.BuildTopology(); // use indices so an edge can be removed no matter what "ref" var edges = new IntSet(clippedMesh.EdgeCount); foreach (var e in clippedMesh.Edges) { if (e.IsValid) { edges.Add(e.Index); } } var capFaceEdges = new List <PolyMesh.Edge>(); var capFaceEdgeSet = new IntSet(); while (edges.Count > 0) { var e = clippedMesh.GetEdge(edges.First()); edges.Remove(e.Index); if (e.IsAnyBorder && vertexOnPlane[e.FromVertexIndex] && vertexOnPlane[e.ToVertexIndex]) { // try to find other edges along the plane // keep set of all edges so in case there the loop runs into a degenerated case an exit is possible (will generate degenerated face) capFaceEdges.Clear(); capFaceEdgeSet.Clear(); var currEdge = e; do { if (currEdge.IsValid) { capFaceEdges.Add(currEdge); capFaceEdgeSet.Add(currEdge.Index); } // find next edge at start-vertex along plane // the new cap face should have winding order start<-to becaues it is on the opposite of the current face-edge currEdge = currEdge.FromVertex.Edges .Select(x => x.FromVertexIndex == currEdge.FromVertexIndex ? x.Opposite : x) .FirstOrDefault(x => x.IsAnyBorder && x.Index != currEdge.Index && vertexOnPlane[x.FromVertexIndex], PolyMesh.Edge.Invalid); } while (currEdge.IsValid && currEdge.Index != e.Index && !capFaceEdgeSet.Contains(currEdge.Index)); if (capFaceEdges.Count > 2) { // add cap-face foreach (var fe in capFaceEdges.Skip(1)) { edges.Remove(fe.Index); } clippedMesh.AddFace(capFaceEdges.Select(fe => fe.ToVertexIndex).ToArray()); } } } // clear topology (is invalid if face has been added) clippedMesh.ClearTopology(); return(clippedMesh); }