예제 #1
0
        /// <summary>
        /// construct EdgeLoop from a list of vertices of mesh
        /// if loop is a boundary edge, we can correct orientation if requested
        /// </summary>
        public static EdgeLoop FromVertices(DMesh3 mesh, IList <int> vertices, bool bAutoOrient = true)
        {
            int[] Vertices = new int[vertices.Count];
            for (int i = 0; i < Vertices.Length; i++)
            {
                Vertices[i] = vertices[i];
            }

            if (bAutoOrient)
            {
                int a = Vertices[0], b = Vertices[1];
                int eid = mesh.FindEdge(a, b);
                if (mesh.IsBoundaryEdge(eid))
                {
                    Index2i ev = mesh.GetOrientedBoundaryEdgeV(eid);
                    if (ev.a == b && ev.b == a)
                    {
                        Array.Reverse(Vertices);
                    }
                }
            }

            int[] Edges = new int[Vertices.Length];
            for (int i = 0; i < Edges.Length; ++i)
            {
                int a = Vertices[i], b = Vertices[(i + 1) % Vertices.Length];
                Edges[i] = mesh.FindEdge(a, b);
                if (Edges[i] == DMesh3.InvalidID)
                {
                    throw new Exception("EdgeLoop.FromVertices: invalid edge [" + a + "," + b + "]");
                }
            }

            return(new EdgeLoop(mesh, Vertices, Edges, false));
        }
예제 #2
0
 public bool IsInternalSpan()
 {
     int NV = Vertices.Length;
     for (int i = 0; i < NV-1; ++i ) {
         int eid = Mesh.FindEdge(Vertices[i], Vertices[i + 1]);
         Debug.Assert(eid != DMesh3.InvalidID);
         if (Mesh.IsBoundaryEdge(eid))
             return false;
     }
     return true;
 }
예제 #3
0
 public void AppendSegments(double r)
 {
     foreach (var seg in Segments)
     {
         Segment3d s = new Segment3d(seg.v0.v, seg.v1.v);
         if (Target.FindEdge(seg.v0.vtx_id, seg.v1.vtx_id) == DMesh3.InvalidID)
         {
             MeshEditor.AppendLine(Target, s, (float)r);
         }
     }
 }
예제 #4
0
        public bool IsInternalLoop()
        {
            int NV = Vertices.Length;

            for (int i = 0; i < NV; ++i)
            {
                int eid = Mesh.FindEdge(Vertices[i], Vertices[(i + 1) % NV]);
                Debug.Assert(eid != DMesh3.InvalidID);
                if (Mesh.edge_is_boundary(eid))
                {
                    return(false);
                }
            }
            return(true);
        }
예제 #5
0
        public int MapEdgeToBaseMesh(int sub_eid)
        {
            Index2i sub_ev  = SubMesh.GetEdgeV(sub_eid);
            Index2i base_ev = MapVerticesToBaseMesh(sub_ev);

            return(BaseMesh.FindEdge(base_ev.a, base_ev.b));
        }
        // for all vertices in loopV, constrain to target
        // for all edges in loopV, disable flips and constrain to target
        public static void ConstrainVtxLoopTo(MeshConstraints cons, DMesh3 mesh, int[] loopV, IProjectionTarget target, int setID = -1)
        {
            VertexConstraint vc = new VertexConstraint(target);

            for (int i = 0; i < loopV.Length; ++i)
            {
                cons.SetOrUpdateVertexConstraint(loopV[i], vc);
            }

            EdgeConstraint ec = new EdgeConstraint(EdgeRefineFlags.NoFlip, target);

            ec.TrackingSetID = setID;
            for (int i = 0; i < loopV.Length; ++i)
            {
                int v0 = loopV[i];
                int v1 = loopV[(i + 1) % loopV.Length];

                int eid = mesh.FindEdge(v0, v1);
                Debug.Assert(eid != DMesh3.InvalidID);
                if (eid != DMesh3.InvalidID)
                {
                    cons.SetOrUpdateEdgeConstraint(eid, ec);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// if this is a border edge-loop, we can check that it is oriented correctly, and
        /// if not, reverse it.
        /// Returns true if we reversed orientation.
        /// </summary>
        public bool CorrectOrientation()
        {
            int a = Vertices[0], b = Vertices[1];
            int eid = Mesh.FindEdge(a, b);

            if (Mesh.IsBoundaryEdge(eid))
            {
                Index2i ev = Mesh.GetOrientedBoundaryEdgeV(eid);
                if (ev.a == b && ev.b == a)
                {
                    Reverse();
                    return(true);
                }
            }
            return(false);
        }
예제 #8
0
        // for all vertices in loopV, constrain to target
        // for all edges in loopV, disable flips and constrain to target
        public static void ConstrainVtxSpanTo(MeshConstraints cons, DMesh3 mesh, IList <int> spanV, IProjectionTarget target, int setID = -1)
        {
            VertexConstraint vc = new VertexConstraint(target);
            int N = spanV.Count;

            for (int i = 0; i < N; ++i)
            {
                cons.SetOrUpdateVertexConstraint(spanV[i], vc);
            }

            EdgeConstraint ec = new EdgeConstraint(EdgeRefineFlags.NoFlip, target);

            ec.TrackingSetID = setID;
            for (int i = 0; i < N - 1; ++i)
            {
                int v0 = spanV[i];
                int v1 = spanV[i + 1];

                int eid = mesh.FindEdge(v0, v1);
                Debug.Assert(eid != DMesh3.InvalidID);
                if (eid != DMesh3.InvalidID)
                {
                    cons.SetOrUpdateEdgeConstraint(eid, ec);
                }
            }
        }
예제 #9
0
        public int MapEdgeToSubmesh(int base_eid)
        {
            Index2i base_ev = BaseMesh.GetEdgeV(base_eid);
            Index2i sub_ev  = MapVerticesToSubmesh(base_ev);

            return(SubMesh.FindEdge(sub_ev.a, sub_ev.b));
        }
예제 #10
0
 /// <summary>
 /// Convert vertex span to list of edges. This should be somewhere else.
 /// </summary>
 public static int[] VerticesToEdges(DMesh3 mesh, int[] vertex_span)
 {
     int NV = vertex_span.Length;
     int[] edges = new int[NV-1];
     for ( int i = 0; i < NV-1; ++i ) {
         int v0 = vertex_span[i];
         int v1 = vertex_span[(i + 1)];
         edges[i] = mesh.FindEdge(v0, v1);
     }
     return edges;
 }
예제 #11
0
        /// <summary>
        /// Convert a vertex loop to an edge loop. This should be somewhere else...
        /// </summary>
        public static int[] VertexLoopToEdgeLoop(DMesh3 mesh, int[] vertex_loop)
        {
            int NV = vertex_loop.Length;

            int[] edges = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                int v0 = vertex_loop[i];
                int v1 = vertex_loop[(i + 1) % NV];
                edges[i] = mesh.FindEdge(v0, v1);
            }
            return(edges);
        }
예제 #12
0
        void add_edge_pos(int a, int b, Vector3d crossing_pos)
        {
            int eid = Mesh.FindEdge(a, b);

            if (eid == DMesh3.InvalidID)
            {
                throw new Exception("MeshIsoCurves.add_edge_split: invalid edge?");
            }
            if (EdgeLocations.ContainsKey(eid))
            {
                return;
            }
            EdgeLocations[eid] = crossing_pos;
        }
예제 #13
0
        /// <summary>
        /// construct EdgeLoop from a list of vertices of mesh
        /// </summary>
        public static EdgeLoop FromVertices(DMesh3 mesh, IList <int> vertices)
        {
            int[] Vertices = new int[vertices.Count];
            for (int i = 0; i < Vertices.Length; i++)
            {
                Vertices[i] = vertices[i];
            }

            int[] Edges = new int[Vertices.Length];
            for (int i = 0; i < Edges.Length; ++i)
            {
                Edges[i] = mesh.FindEdge(Vertices[i], Vertices[(i + 1) % Vertices.Length]);
            }

            return(new EdgeLoop(mesh, Vertices, Edges, false));
        }
예제 #14
0
        /// <summary>
        /// given list of edges of MeshA, and vertex map from A to B, map to list of edges on B
        /// </summary>
        public static List <int> MapEdgesViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, List <int> edges)
        {
            int        N      = edges.Count;
            List <int> result = new List <int>(N);

            for (int i = 0; i < N; ++i)
            {
                int     eid_a = edges[i];
                Index2i aev   = MeshA.GetEdgeV(eid_a);
                int     bev0  = AtoBV[aev.a];
                int     bev1  = AtoBV[aev.b];
                int     eid_b = MeshB.FindEdge(bev0, bev1);
                Debug.Assert(eid_b != DMesh3.InvalidID);
                result.Add(eid_b);
            }
            return(result);
        }
예제 #15
0
        /// <summary>
        /// Check if all edges of this loop are boundary edges.
        /// If testMesh != null, will check that mesh instead of internal Mesh
        /// </summary>
        public bool IsBoundaryLoop(DMesh3 testMesh = null)
        {
            DMesh3 useMesh = (testMesh != null) ? testMesh : Mesh;

            int NV = Vertices.Length;

            for (int i = 0; i < NV; ++i)
            {
                int eid = useMesh.FindEdge(Vertices[i], Vertices[(i + 1) % NV]);
                Debug.Assert(eid != DMesh3.InvalidID);
                if (useMesh.IsBoundaryEdge(eid) == false)
                {
                    return(false);
                }
            }
            return(true);
        }
예제 #16
0
        /// <summary>
        /// construct EdgeSpan from a list of vertices of mesh
        /// </summary>
        public static EdgeSpan FromVertices(DMesh3 mesh, IList <int> vertices)
        {
            int NV = vertices.Count;

            int[] Vertices = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                Vertices[i] = vertices[i];
            }
            int NE = NV - 1;

            int[] Edges = new int[NE];
            for (int i = 0; i < NE; ++i)
            {
                Edges[i] = mesh.FindEdge(Vertices[i], Vertices[i + 1]);
                if (Edges[i] == DMesh3.InvalidID)
                {
                    throw new Exception("EdgeSpan.FromVertices: vertices are not connected by edge!");
                }
            }
            return(new EdgeSpan(mesh, Vertices, Edges, false));
        }
예제 #17
0
        /// <summary>
        /// given EdgeLoop on MeshA, and vertex map from A to B, map to EdgeLoop on B
        /// </summary>
        public static EdgeLoop MapLoopViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, EdgeLoop loopIn)
        {
            int NV = loopIn.VertexCount, NE = loopIn.EdgeCount;

            int[] newVerts = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                newVerts[i] = AtoBV[loopIn.Vertices[i]];
            }

            int[] newEdges = new int[NE];
            for (int i = 0; i < NE; ++i)
            {
                int     eid_a = loopIn.Edges[i];
                Index2i aev   = MeshA.GetEdgeV(eid_a);
                int     bev0  = AtoBV[aev.a];
                int     bev1  = AtoBV[aev.b];
                newEdges[i] = MeshB.FindEdge(bev0, bev1);
                Debug.Assert(newEdges[i] != DMesh3.InvalidID);
            }

            return(new EdgeLoop(MeshB, newVerts, newEdges, false));
        }
예제 #18
0
        public static ValidationStatus IsBoundaryLoop(DMesh3 mesh, EdgeLoop loop)
        {
            int N = loop.Vertices.Length;

            for (int i = 0; i < N; ++i)
            {
                if (!mesh.vertex_is_boundary(loop.Vertices[i]))
                {
                    return(ValidationStatus.NotBoundaryVertex);
                }
            }

            for (int i = 0; i < N; ++i)
            {
                int a = loop.Vertices[i];
                int b = loop.Vertices[(i + 1) % N];

                int eid = mesh.FindEdge(a, b);
                if (eid == DMesh3.InvalidID)
                {
                    return(ValidationStatus.VerticesNotConnectedByEdge);
                }

                if (mesh.edge_is_boundary(eid) == false)
                {
                    return(ValidationStatus.NotBoundaryEdge);
                }

                Index2i ev = mesh.GetOrientedBoundaryEdgeV(eid);
                if (!(ev.a == a && ev.b == b))
                {
                    return(ValidationStatus.IncorrectLoopOrientation);
                }
            }

            return(ValidationStatus.Ok);
        }
예제 #19
0
        public static ValidationStatus IsEdgeLoop(DMesh3 mesh, EdgeLoop loop)
        {
            int N = loop.Vertices.Length;

            for (int i = 0; i < N; ++i)
            {
                if (!mesh.IsVertex(loop.Vertices[i]))
                {
                    return(ValidationStatus.NotAVertex);
                }
            }
            for (int i = 0; i < N; ++i)
            {
                int a = loop.Vertices[i];
                int b = loop.Vertices[(i + 1) % N];

                int eid = mesh.FindEdge(a, b);
                if (eid == DMesh3.InvalidID)
                {
                    return(ValidationStatus.VerticesNotConnectedByEdge);
                }
            }
            return(ValidationStatus.Ok);
        }
        public virtual bool Apply()
        {
            HashSet <int> OnCurveVerts = new HashSet <int>();     // original vertices that were epsilon-coincident w/ curve vertices

            insert_corners(OnCurveVerts);

            // [RMS] not using this?
            //HashSet<int> corner_v = new HashSet<int>(CurveVertices);

            // not sure we need to track all of these
            HashSet <int> ZeroEdges    = new HashSet <int>();
            HashSet <int> ZeroVertices = new HashSet <int>();

            OnCutEdges = new HashSet <int>();

            HashSet <int> NewEdges       = new HashSet <int>();
            HashSet <int> NewCutVertices = new HashSet <int>();

            sbyte[] signs = new sbyte[2 * Mesh.MaxVertexID + 2 * Curve.VertexCount];

            HashSet <int> segTriangles = new HashSet <int>();
            HashSet <int> segVertices  = new HashSet <int>();
            HashSet <int> segEdges     = new HashSet <int>();

            // loop over segments, insert each one in sequence
            int N = (IsLoop) ? Curve.VertexCount : Curve.VertexCount - 1;

            for (int si = 0; si < N; ++si)
            {
                int       i0  = si;
                int       i1  = (si + 1) % Curve.VertexCount;
                Segment2d seg = new Segment2d(Curve[i0], Curve[i1]);

                int i0_vid = CurveVertices[i0];
                int i1_vid = CurveVertices[i1];

                // If these vertices are already connected by an edge, we can just continue.
                int existing_edge = Mesh.FindEdge(i0_vid, i1_vid);
                if (existing_edge != DMesh3.InvalidID)
                {
                    add_cut_edge(existing_edge);
                    continue;
                }

                if (triSpatial != null)
                {
                    segTriangles.Clear(); segVertices.Clear(); segEdges.Clear();
                    AxisAlignedBox2d segBounds = new AxisAlignedBox2d(seg.P0); segBounds.Contain(seg.P1);
                    segBounds.Expand(MathUtil.ZeroTolerancef * 10);
                    triSpatial.FindTrianglesInRange(segBounds, segTriangles);
                    IndexUtil.TrianglesToVertices(Mesh, segTriangles, segVertices);
                    IndexUtil.TrianglesToEdges(Mesh, segTriangles, segEdges);
                }

                int MaxVID = Mesh.MaxVertexID;
                IEnumerable <int> vertices = Interval1i.Range(MaxVID);
                if (triSpatial != null)
                {
                    vertices = segVertices;
                }

                // compute edge-crossing signs
                // [TODO] could walk along mesh from a to b, rather than computing for entire mesh?
                if (signs.Length < MaxVID)
                {
                    signs = new sbyte[2 * MaxVID];
                }
                gParallel.ForEach(vertices, (vid) => {
                    if (Mesh.IsVertex(vid))
                    {
                        if (vid == i0_vid || vid == i1_vid)
                        {
                            signs[vid] = 0;
                        }
                        else
                        {
                            Vector2d v2 = PointF(vid);
                            // tolerance defines band in which we will consider values to be zero
                            signs[vid] = (sbyte)seg.WhichSide(v2, SpatialEpsilon);
                        }
                    }
                    else
                    {
                        signs[vid] = sbyte.MaxValue;
                    }
                });

                // have to skip processing of new edges. If edge id
                // is > max at start, is new. Otherwise if in NewEdges list, also new.
                // (need both in case we re-use an old edge index)
                int MaxEID = Mesh.MaxEdgeID;
                NewEdges.Clear();
                NewCutVertices.Clear();
                NewCutVertices.Add(i0_vid);
                NewCutVertices.Add(i1_vid);

                // cut existing edges with segment
                IEnumerable <int> edges = Interval1i.Range(MaxEID);
                if (triSpatial != null)
                {
                    edges = segEdges;
                }
                foreach (int eid in edges)
                {
                    if (Mesh.IsEdge(eid) == false)
                    {
                        continue;
                    }
                    if (eid >= MaxEID || NewEdges.Contains(eid))
                    {
                        continue;
                    }

                    // cannot cut boundary edges?
                    if (Mesh.IsBoundaryEdge(eid))
                    {
                        continue;
                    }

                    Index2i ev       = Mesh.GetEdgeV(eid);
                    int     eva_sign = signs[ev.a];
                    int     evb_sign = signs[ev.b];

                    // [RMS] should we be using larger epsilon here? If we don't track OnCurveVerts explicitly, we
                    // need to at least use same epsilon we passed to insert_corner_from_bary...do we still also
                    // need that to catch the edges we split in the poke?
                    bool eva_in_segment = false;
                    if (eva_sign == 0)
                    {
                        eva_in_segment = OnCurveVerts.Contains(ev.a) || Math.Abs(seg.Project(PointF(ev.a))) < (seg.Extent + SpatialEpsilon);
                    }
                    bool evb_in_segment = false;
                    if (evb_sign == 0)
                    {
                        evb_in_segment = OnCurveVerts.Contains(ev.b) || Math.Abs(seg.Project(PointF(ev.b))) < (seg.Extent + SpatialEpsilon);
                    }

                    // If one or both vertices are on-segment, we have special case.
                    // If just one vertex is on the segment, we can skip this edge.
                    // If both vertices are on segment, then we can just re-use this edge.
                    if (eva_in_segment || evb_in_segment)
                    {
                        if (eva_in_segment && evb_in_segment)
                        {
                            ZeroEdges.Add(eid);
                            add_cut_edge(eid);
                            NewCutVertices.Add(ev.a); NewCutVertices.Add(ev.b);
                        }
                        else
                        {
                            int zvid = eva_in_segment ? ev.a : ev.b;
                            ZeroVertices.Add(zvid);
                            NewCutVertices.Add(zvid);
                        }
                        continue;
                    }

                    // no crossing
                    if (eva_sign * evb_sign > 0)
                    {
                        continue;
                    }

                    // compute segment/segment intersection
                    Vector2d             va       = PointF(ev.a);
                    Vector2d             vb       = PointF(ev.b);
                    Segment2d            edge_seg = new Segment2d(va, vb);
                    IntrSegment2Segment2 intr     = new IntrSegment2Segment2(seg, edge_seg);
                    intr.Compute();
                    if (intr.Type == IntersectionType.Segment)
                    {
                        // [RMS] we should have already caught this above, so if it happens here it is probably spurious?
                        // we should have caught this case above, but numerics are different so it might occur again
                        ZeroEdges.Add(eid);
                        NewCutVertices.Add(ev.a); NewCutVertices.Add(ev.b);
                        add_cut_edge(eid);
                        continue;
                    }
                    else if (intr.Type != IntersectionType.Point)
                    {
                        continue; // no intersection
                    }
                    Vector2d x = intr.Point0;
                    double   t = Math.Sqrt(x.DistanceSquared(va) / va.DistanceSquared(vb));

                    // this case happens if we aren't "on-segment" but after we do the test the intersection pt
                    // is within epsilon of one end of the edge. This is a spurious t-intersection and we
                    // can ignore it. Some other edge should exist that picks up this vertex as part of it.
                    // [TODO] what about if this edge is degenerate?
                    bool x_in_segment = Math.Abs(edge_seg.Project(x)) < (edge_seg.Extent - SpatialEpsilon);
                    if (!x_in_segment)
                    {
                        continue;
                    }

                    Index2i et = Mesh.GetEdgeT(eid);
                    spatial_remove_triangles(et.a, et.b);

                    // split edge at this segment
                    DMesh3.EdgeSplitInfo splitInfo;
                    MeshResult           result = Mesh.SplitEdge(eid, out splitInfo, t);
                    if (result != MeshResult.Ok)
                    {
                        throw new Exception("MeshInsertUVSegment.Apply: SplitEdge failed - " + result.ToString());
                        //return false;
                    }

                    // move split point to intersection position
                    SetPointF(splitInfo.vNew, x);
                    NewCutVertices.Add(splitInfo.vNew);

                    NewEdges.Add(splitInfo.eNewBN);
                    NewEdges.Add(splitInfo.eNewCN);

                    spatial_add_triangles(et.a, et.b);
                    spatial_add_triangles(splitInfo.eNewT2, splitInfo.eNewT3);

                    // some splits - but not all - result in new 'other' edges that are on
                    // the polypath. We want to keep track of these edges so we can extract loop later.
                    Index2i ecn = Mesh.GetEdgeV(splitInfo.eNewCN);
                    if (NewCutVertices.Contains(ecn.a) && NewCutVertices.Contains(ecn.b))
                    {
                        add_cut_edge(splitInfo.eNewCN);
                    }

                    // since we don't handle bdry edges this should never be false, but maybe we will handle bdry later...
                    if (splitInfo.eNewDN != DMesh3.InvalidID)
                    {
                        NewEdges.Add(splitInfo.eNewDN);
                        Index2i edn = Mesh.GetEdgeV(splitInfo.eNewDN);
                        if (NewCutVertices.Contains(edn.a) && NewCutVertices.Contains(edn.b))
                        {
                            add_cut_edge(splitInfo.eNewDN);
                        }
                    }
                }
            }

            // extract the cut paths
            if (EnableCutSpansAndLoops)
            {
                find_cut_paths(OnCutEdges);
            }

            return(true);
        }         // Apply()
예제 #21
0
        /// <summary>
        /// Check if this m2 is the same as this mesh. By default only checks
        /// vertices and triangles, turn on other parameters w/ flags
        /// </summary>
        public bool IsSameMesh(DMesh3 m2, bool bCheckConnectivity, bool bCheckEdgeIDs = false,
                               bool bCheckNormals = false, bool bCheckColors = false, bool bCheckUVs = false,
                               bool bCheckGroups  = false,
                               float Epsilon      = MathUtil.Epsilonf)
        {
            if (VertexCount != m2.VertexCount)
            {
                return(false);
            }

            if (TriangleCount != m2.TriangleCount)
            {
                return(false);
            }

            foreach (int vid in VertexIndices())
            {
                if (m2.IsVertex(vid) == false || GetVertex(vid).EpsilonEqual(m2.GetVertex(vid), Epsilon) == false)
                {
                    return(false);
                }
            }
            foreach (int tid in TriangleIndices())
            {
                if (m2.IsTriangle(tid) == false || GetTriangle(tid).Equals(m2.GetTriangle(tid)) == false)
                {
                    return(false);
                }
            }
            if (bCheckConnectivity)
            {
                foreach (int eid in EdgeIndices())
                {
                    Index4i e         = GetEdge(eid);
                    int     other_eid = m2.FindEdge(e.a, e.b);
                    if (other_eid == InvalidID)
                    {
                        return(false);
                    }

                    Index4i oe = m2.GetEdge(other_eid);
                    if (Math.Min(e.c, e.d) != Math.Min(oe.c, oe.d) || Math.Max(e.c, e.d) != Math.Max(oe.c, oe.d))
                    {
                        return(false);
                    }
                }
            }
            if (bCheckEdgeIDs)
            {
                if (EdgeCount != m2.EdgeCount)
                {
                    return(false);
                }

                foreach (int eid in EdgeIndices())
                {
                    if (m2.IsEdge(eid) == false || GetEdge(eid).Equals(m2.GetEdge(eid)) == false)
                    {
                        return(false);
                    }
                }
            }
            if (bCheckNormals)
            {
                if (HasVertexNormals != m2.HasVertexNormals)
                {
                    return(false);
                }

                if (HasVertexNormals)
                {
                    foreach (int vid in VertexIndices())
                    {
                        if (GetVertexNormal(vid).EpsilonEqual(m2.GetVertexNormal(vid), Epsilon) == false)
                        {
                            return(false);
                        }
                    }
                }
            }
            if (bCheckColors)
            {
                if (HasVertexColors != m2.HasVertexColors)
                {
                    return(false);
                }

                if (HasVertexColors)
                {
                    foreach (int vid in VertexIndices())
                    {
                        if (GetVertexColor(vid).EpsilonEqual(m2.GetVertexColor(vid), Epsilon) == false)
                        {
                            return(false);
                        }
                    }
                }
            }
            if (bCheckUVs)
            {
                if (HasVertexUVs != m2.HasVertexUVs)
                {
                    return(false);
                }

                if (HasVertexUVs)
                {
                    foreach (int vid in VertexIndices())
                    {
                        if (GetVertexUV(vid).EpsilonEqual(m2.GetVertexUV(vid), Epsilon) == false)
                        {
                            return(false);
                        }
                    }
                }
            }
            if (bCheckGroups)
            {
                if (HasTriangleGroups != m2.HasTriangleGroups)
                {
                    return(false);
                }

                if (HasTriangleGroups)
                {
                    foreach (int tid in TriangleIndices())
                    {
                        if (GetTriangleGroup(tid) != m2.GetTriangleGroup(tid))
                        {
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
예제 #22
0
        public virtual bool Apply()
        {
            insert_corners();

            // [RMS] not using this?
            //HashSet<int> corner_v = new HashSet<int>(CurveVertices);

            // not sure we need to track all of these
            HashSet <int> ZeroEdges    = new HashSet <int>();
            HashSet <int> ZeroVertices = new HashSet <int>();

            OnCutEdges = new HashSet <int>();

            // loop over segments, insert each one in sequence
            int N = (IsLoop) ? Curve.VertexCount : Curve.VertexCount - 1;

            for (int si = 0; si < N; ++si)
            {
                int       i0  = si;
                int       i1  = (si + 1) % Curve.VertexCount;
                Segment2d seg = new Segment2d(Curve[i0], Curve[i1]);

                int i0_vid = CurveVertices[i0];
                int i1_vid = CurveVertices[i1];

                // If these vertices are already connected by an edge, we can just continue.
                int existing_edge = Mesh.FindEdge(i0_vid, i1_vid);
                if (existing_edge != DMesh3.InvalidID)
                {
                    OnCutEdges.Add(existing_edge);
                    continue;
                }

                // compute edge-crossing signs
                // [TODO] could walk along mesh from a to b, rather than computing for entire mesh?
                int   MaxVID = Mesh.MaxVertexID;
                int[] signs  = new int[MaxVID];
                gParallel.ForEach(Interval1i.Range(MaxVID), (vid) => {
                    if (Mesh.IsVertex(vid))
                    {
                        if (vid == i0_vid || vid == i1_vid)
                        {
                            signs[vid] = 0;
                        }
                        else
                        {
                            Vector2d v2 = PointF(vid);
                            // tolerance defines band in which we will consider values to be zero
                            signs[vid] = seg.WhichSide(v2, MathUtil.ZeroTolerance);
                        }
                    }
                    else
                    {
                        signs[vid] = int.MaxValue;
                    }
                });

                // have to skip processing of new edges. If edge id
                // is > max at start, is new. Otherwise if in NewEdges list, also new.
                // (need both in case we re-use an old edge index)
                int           MaxEID         = Mesh.MaxEdgeID;
                HashSet <int> NewEdges       = new HashSet <int>();
                HashSet <int> NewCutVertices = new HashSet <int>();
                NewCutVertices.Add(i0_vid);
                NewCutVertices.Add(i1_vid);

                // cut existing edges with segment
                for (int eid = 0; eid < MaxEID; ++eid)
                {
                    if (Mesh.IsEdge(eid) == false)
                    {
                        continue;
                    }
                    if (eid >= MaxEID || NewEdges.Contains(eid))
                    {
                        continue;
                    }

                    // cannot cut boundary edges?
                    if (Mesh.IsBoundaryEdge(eid))
                    {
                        continue;
                    }

                    Index2i ev       = Mesh.GetEdgeV(eid);
                    int     eva_sign = signs[ev.a];
                    int     evb_sign = signs[ev.b];

                    bool eva_in_segment = false;
                    if (eva_sign == 0)
                    {
                        eva_in_segment = Math.Abs(seg.Project(PointF(ev.a))) < (seg.Extent + MathUtil.ZeroTolerance);
                    }
                    bool evb_in_segment = false;
                    if (evb_sign == 0)
                    {
                        evb_in_segment = Math.Abs(seg.Project(PointF(ev.b))) < (seg.Extent + MathUtil.ZeroTolerance);
                    }

                    // If one or both vertices are on-segment, we have special case.
                    // If just one vertex is on the segment, we can skip this edge.
                    // If both vertices are on segment, then we can just re-use this edge.
                    if (eva_in_segment || evb_in_segment)
                    {
                        if (eva_in_segment && evb_in_segment)
                        {
                            ZeroEdges.Add(eid);
                            OnCutEdges.Add(eid);
                        }
                        else
                        {
                            ZeroVertices.Add(eva_in_segment ? ev.a : ev.b);
                        }
                        continue;
                    }

                    // no crossing
                    if (eva_sign * evb_sign > 0)
                    {
                        continue;
                    }

                    // compute segment/segment intersection
                    Vector2d             va       = PointF(ev.a);
                    Vector2d             vb       = PointF(ev.b);
                    Segment2d            edge_seg = new Segment2d(va, vb);
                    IntrSegment2Segment2 intr     = new IntrSegment2Segment2(seg, edge_seg);
                    intr.Compute();
                    if (intr.Type == IntersectionType.Segment)
                    {
                        // [RMS] we should have already caught this above, so if it happens here it is probably spurious?
                        // we should have caught this case above, but numerics are different so it might occur again
                        ZeroEdges.Add(eid);
                        OnCutEdges.Add(eid);
                        continue;
                    }
                    else if (intr.Type != IntersectionType.Point)
                    {
                        continue; // no intersection
                    }
                    Vector2d x = intr.Point0;

                    // this case happens if we aren't "on-segment" but after we do the test the intersection pt
                    // is within epsilon of one end of the edge. This is a spurious t-intersection and we
                    // can ignore it. Some other edge should exist that picks up this vertex as part of it.
                    // [TODO] what about if this edge is degenerate?
                    bool x_in_segment = Math.Abs(edge_seg.Project(x)) < (edge_seg.Extent - MathUtil.ZeroTolerance);
                    if (!x_in_segment)
                    {
                        continue;
                    }

                    // split edge at this segment
                    DMesh3.EdgeSplitInfo splitInfo;
                    MeshResult           result = Mesh.SplitEdge(eid, out splitInfo);
                    if (result != MeshResult.Ok)
                    {
                        throw new Exception("MeshInsertUVSegment.Cut: failed in SplitEdge");
                        //return false;
                    }

                    // move split point to intersection position
                    SetPointF(splitInfo.vNew, x);
                    NewCutVertices.Add(splitInfo.vNew);

                    NewEdges.Add(splitInfo.eNewBN);
                    NewEdges.Add(splitInfo.eNewCN);

                    // some splits - but not all - result in new 'other' edges that are on
                    // the polypath. We want to keep track of these edges so we can extract loop later.
                    Index2i ecn = Mesh.GetEdgeV(splitInfo.eNewCN);
                    if (NewCutVertices.Contains(ecn.a) && NewCutVertices.Contains(ecn.b))
                    {
                        OnCutEdges.Add(splitInfo.eNewCN);
                    }

                    // since we don't handle bdry edges this should never be false, but maybe we will handle bdry later...
                    if (splitInfo.eNewDN != DMesh3.InvalidID)
                    {
                        NewEdges.Add(splitInfo.eNewDN);
                        Index2i edn = Mesh.GetEdgeV(splitInfo.eNewDN);
                        if (NewCutVertices.Contains(edn.a) && NewCutVertices.Contains(edn.b))
                        {
                            OnCutEdges.Add(splitInfo.eNewDN);
                        }
                    }
                }
            }


            //MeshEditor editor = new MeshEditor(Mesh);
            //foreach (int eid in OnCutEdges)
            //    editor.AppendBox(new Frame3f(Mesh.GetEdgePoint(eid, 0.5)), 0.1f);
            //Util.WriteDebugMesh(Mesh, string.Format("C:\\git\\geometry3SharpDemos\\geometry3Test\\test_output\\after_inserted.obj"));


            // extract the cut paths
            if (EnableCutSpansAndLoops)
            {
                find_cut_paths(OnCutEdges);
            }

            return(true);
        }         // Apply()
예제 #23
0
        /// <summary>
        /// Disconnect the given triangles from their neighbours, by duplicating "boundary" vertices, ie
        /// vertices on edges for which one triangle is in-set and the other is not.
        /// If bComputeEdgePairs is true, we return list of old/new edge pairs (useful for stitching)
        /// [TODO] currently boundary-edge behaviour is to *not* duplicate boundary verts
        /// </summary>
        public bool SeparateTriangles(IEnumerable <int> triangles, bool bComputeEdgePairs, out List <Index2i> EdgePairs)
        {
            HashSet <int>         in_set    = new HashSet <int>(triangles);
            Dictionary <int, int> VertexMap = new Dictionary <int, int>();

            EdgePairs = null;
            HashSet <int>  edges        = null;
            List <Index2i> OldEdgeVerts = null;

            if (bComputeEdgePairs)
            {
                EdgePairs    = new List <Index2i>();
                edges        = new HashSet <int>();
                OldEdgeVerts = new List <Index2i>();
            }

            // duplicate vertices on edges that are on boundary of triangles roi
            foreach (int tid in triangles)
            {
                Index3i te = Mesh.GetTriEdges(tid);

                for (int j = 0; j < 3; ++j)
                {
                    Index2i et = Mesh.GetEdgeT(te[j]);
                    // [TODO] what about behavior where we want to also duplicate boundary verts??
                    if (et.b == DMesh3.InvalidID || (et.a == tid && in_set.Contains(et.b)) || (et.b == tid && in_set.Contains(et.a)))
                    {
                        te[j] = -1;
                    }
                }

                for (int j = 0; j < 3; ++j)
                {
                    if (te[j] == -1)
                    {
                        continue;
                    }
                    Index2i ev = Mesh.GetEdgeV(te[j]);
                    if (VertexMap.ContainsKey(ev.a) == false)
                    {
                        VertexMap[ev.a] = Mesh.AppendVertex(Mesh, ev.a);
                    }
                    if (VertexMap.ContainsKey(ev.b) == false)
                    {
                        VertexMap[ev.b] = Mesh.AppendVertex(Mesh, ev.b);
                    }

                    if (bComputeEdgePairs && edges.Contains(te[j]) == false)
                    {
                        edges.Add(te[j]);
                        OldEdgeVerts.Add(ev);
                        EdgePairs.Add(new Index2i(te[j], -1));
                    }
                }
            }

            // update triangles
            foreach (int tid in triangles)
            {
                Index3i tv     = Mesh.GetTriangle(tid);
                Index3i tv_new = tv;
                for (int j = 0; j < 3; ++j)
                {
                    int newv;
                    if (VertexMap.TryGetValue(tv[j], out newv))
                    {
                        tv_new[j] = newv;
                    }
                }
                if (tv_new != tv)
                {
                    Mesh.SetTriangle(tid, tv_new);
                }
            }

            if (bComputeEdgePairs)
            {
                for (int k = 0; k < EdgePairs.Count; ++k)
                {
                    Index2i old_ev  = OldEdgeVerts[k];
                    int     new_a   = VertexMap[old_ev.a];
                    int     new_b   = VertexMap[old_ev.b];
                    int     new_eid = Mesh.FindEdge(new_a, new_b);
                    Util.gDevAssert(new_eid != DMesh3.InvalidID);
                    EdgePairs[k] = new Index2i(EdgePairs[k].a, new_eid);
                }
            }

            return(true);
        }