예제 #1
0
        public static int Pop(this IntSet self)
        {
            if (self.Count == 0)
            {
                throw new InvalidOperationException();
            }
            int result = self.First();

            self.Remove(result);
            return(result);
        }
예제 #2
0
        /// <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);
        }