コード例 #1
0
        /// <summary>
        /// Insert a new face from a counter-clockwise ordered list of halfedges
        /// </summary>
        /// <param name="edges"></param>
        /// <returns></returns>
        public bool Insert(IReadOnlyList <HalfEdge> edges)
        {
            if (edges.Count < 3)
            {
                return(false);
            }

            // TODO: Check if ccw - ordered
            // establish circular link between edges
            EdgeLinker.LinkOrderedEdgeCollection(edges);

            // assign face starting edge
            var face = new Face {
                Start = edges[0]
            };

            // assign face to edges
            foreach (var edge in edges)
            {
                edge.Face = face;
            }

            // insert the new face
            return(Insert(face));
        }
コード例 #2
0
        /// <summary>
        /// Try to merge the two given faces.
        /// For this to work, the edges belonging to both faces must be able
        /// to form a closed loop.
        /// The first face will be grown and the second face removed on success
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns>True on success, False on failure</returns>
        internal static bool MergeFaces(this Kernel kernel, Face a, Face b)
        {
            // try to find the shared edge
            if (!ConnectivityQuery.TryFindSharedEdge(a, b, out var shared))
            {
                return(false);
            }

            // get edge iterator for face a, starting at shared edge
            var firstEdges = new EdgeIterator(shared).ToArray();

            // get edge iterator for face b starting at shared edge
            var otherEdges = new EdgeIterator(shared.Pair).ToArray();

            // remove the shared edge from the kernel
            kernel.Remove(shared);

            // establish circular link between both face halfes
            EdgeLinker.LinkOrderedEdgeCollection(
                firstEdges
                .Skip(1)
                .Concat(otherEdges.Skip(1))
                .ToList());

            // update face references
            otherEdges.Skip(1).Select(e => e.Face = a);

            // remove face b
            b.Start = null;
            kernel.Remove(b);

            return(true);
        }
コード例 #3
0
        internal static bool TrySplitFace(this Kernel kernel, HalfEdge start, HalfEdge end, out (Face, Face) parts)
        {
            parts = (null, null);
            // TODO: Error checks

            // get edges for face of both halfedges
            var edges = new EdgeIterator(start).ToArray();

            // can't split triangles
            if (edges.Length <= 3)
            {
                return(false);
            }

            // get the index of the end edge inside the edges array
            var endIndex = Array.IndexOf(edges, end);

            // create the new ending halfedge for the start half
            var newEnd = new HalfEdge
            {
                Face     = start.Face,
                Next     = start,
                Previous = edges[endIndex - 1],
                Origin   = end.Origin
            };

            // create the new Face for the end half
            var newFace = new Face {
                Start = end
            };
            // create a new starting edge for the end half
            var newStart = new HalfEdge
            {
                Face     = newFace,
                Next     = end,
                Previous = edges.Last(),
                Origin   = start.Origin,
                Pair     = newEnd
            };

            // pair up the new end
            newEnd.Pair = newStart;

            // establish circular link for first face
            var firstFaceEdges = edges.Take(endIndex).ToList();

            firstFaceEdges.Add(newEnd);
            EdgeLinker.LinkOrderedEdgeCollection(firstFaceEdges);

            // hacky re-assignment
            newEnd.Face.Start = newEnd.Next;

            // establish circular link for second face
            var secondFaceEdges = edges.Skip(endIndex).ToList();

            secondFaceEdges.Insert(0, newStart);
            EdgeLinker.LinkOrderedEdgeCollection(secondFaceEdges);
            secondFaceEdges.ForEach(e => e.Face = newFace);

            // Add new edges to kernel
            kernel.Add(newEnd);
            kernel.Add(newStart);

            // add new face
            kernel.Insert(newFace);

            // prepare output
            parts = (start.Face, newFace);
            return(true);
        }
コード例 #4
0
        /// <summary>
        /// Adds a new face to the kernel
        /// </summary>
        /// <param name="positions"></param>
        public bool AddFace(IEnumerable <Vec3d> positions)
        {
            // No bad faces please :(
            if (positions.Count() < 3)
            {
                return(false);
            }

            // convert positions to vertices inside the mesh
            var vertices = VertexQuery.GetVerticesForPositions(_vertices, positions);

            // if the positions had stacked vertices, we might not be able to continue
            if (vertices.Count() < 3)
            {
                // iterate over position vertices
                foreach (var vertex in vertices)
                {
                    // if the vertex was old, it will have an outgoing
                    if (vertex.Outgoing != null)
                    {
                        continue;
                    }

                    // if it was new we need to remove it to restore state
                    Remove(vertex);
                }

                return(false);
            }

            var edges = new List <HalfEdge>();

            // iterate over all positions
            foreach (var vertex in vertices)
            {
                // create a new halfedge originating from the current vertex and linked to the new face
                var halfEdge = new HalfEdge
                {
                    Origin = vertex,
                };

                // test if the vertex already has an outgoing edge assigned
                if (vertex.Outgoing is null)
                {
                    vertex.Outgoing = halfEdge;
                }

                edges.Add(halfEdge);
            }

            // Insert a face from the edges
            Insert(edges);

            // iterate over all edges and insert them
            foreach (var edge in edges)
            {
                // TODO: Maybe we should NOT skip linking checks here
                _halfEdges.Add(edge);
            }

            // test if first face
            if (this.FaceCount == 1)
            {
                var outerRing = new EdgeIterator(
                    _halfEdges[0])
                                .Select(h => h.Pair)
                                .Reverse()
                                .ToList();

                // establish circular link between outside half-edges
                EdgeLinker.LinkOrderedEdgeCollection(outerRing);
            }

            // TODO: Should be method of edgelinker instead
            // Make sure edge pairs either have a starting face or the ghost face
            // Iterators are lazy, calling `Count()` will execute the select body
            _ = edges.Where(e => e.Pair.Face == null).Select(e => e.Pair.Face = Kernel.Outside).Count();

            return(true);

            // TODO: Make sure outer halfEdges are linked,too
            // TODO: Right now only inner halfEdges are linked circularly
            // TODO: This leads to crashes on faces with too many naked edges when creating vertexringiterators
            // TODO: For this we will need a 'ghost' face that encompasses all the space outside of the mesh faces
            // TODO: CLosed meshes will have an empty ghost face
        }
コード例 #5
0
        internal static void Kis(this Kernel kernel)
        {
            var initialFaceCount = kernel.FaceCount;

            for (int i = 0; i < initialFaceCount; i++)
            {
                var face = kernel.Faces[i];

                // get face center
                // TODO: We could move the center vertex by face normal direction to build a n - pyramid
                var center = face.GetFaceCenter();

                // get vertex for center
                var centerVertex = kernel.GetVertexForPosition(center);

                var newCenter = true;

                // iterate over face edges
                foreach (var edge in new EdgeIterator(face.Start))
                {
                    // new face that will be created
                    var newFace = new Face {
                        Start = edge
                    };

                    // link up current edge
                    edge.Face = newFace;

                    // create an edge from center to origin of current edge
                    if (!kernel.TryGetHalfEdgeBetweenVertices(centerVertex, edge.Origin, out var incoming))
                    {
                        incoming = new HalfEdge
                        {
                            Face   = newFace,
                            Origin = centerVertex
                        };
                    }

                    // create an edge from current edge target to center
                    if (!kernel.TryGetHalfEdgeBetweenVertices(edge.Target, centerVertex, out var outgoing))
                    {
                        outgoing = new HalfEdge
                        {
                            Face   = newFace,
                            Origin = edge.Target,
                        };
                    }

                    // link up center vertex on first iteration
                    if (newCenter)
                    {
                        centerVertex.Outgoing = incoming;
                        newCenter             = false;
                    }

                    // link up edges
                    EdgeLinker.LinkOrderedEdgeCollection(new[] { incoming, edge, outgoing });

                    // add new edges to kernel
                    kernel.Add(incoming);
                    kernel.Add(outgoing);

                    // insert new face into kernel
                    kernel.Insert(newFace);
                }

                // unlink face
                face.Start = null;
            }

            for (int i = initialFaceCount - 1; i >= 0; i--)
            {
                kernel.Remove(kernel.Faces[i]);
            }
        }