Example #1
0
        /// <summary>
        /// if before a flip we have normals (n1,n2) and after we have (m1,m2), check if
        /// the dot between any of the 4 pairs changes sign after the flip, or is
        /// less than the dot-product tolerance (ie angle tolerance)
        /// </summary>
        public static bool CheckIfEdgeFlipCreatesFlip(DMesh3 mesh, int eID, double flip_dot_tol = 0.0)
        {
            Util.gDevAssert(mesh.IsBoundaryEdge(eID) == false);
            Index4i einfo = mesh.GetEdge(eID);
            Index2i ov    = mesh.GetEdgeOpposingV(eID);

            int a = einfo.a, b = einfo.b, c = ov.a, d = ov.b;
            int t0 = einfo.c;

            Vector3d vC = mesh.GetVertex(c), vD = mesh.GetVertex(d);
            Index3i  tri_v = mesh.GetTriangle(t0);
            int      oa = a, ob = b;

            IndexUtil.orient_tri_edge(ref oa, ref ob, ref tri_v);
            Vector3d vOA = mesh.GetVertex(oa), vOB = mesh.GetVertex(ob);
            Vector3d n0 = MathUtil.FastNormalDirection(ref vOA, ref vOB, ref vC);
            Vector3d n1 = MathUtil.FastNormalDirection(ref vOB, ref vOA, ref vD);
            Vector3d f0 = MathUtil.FastNormalDirection(ref vC, ref vD, ref vOB);

            if (edge_flip_metric(ref n0, ref f0, flip_dot_tol) <= flip_dot_tol ||
                edge_flip_metric(ref n1, ref f0, flip_dot_tol) <= flip_dot_tol)
            {
                return(true);
            }
            Vector3d f1 = MathUtil.FastNormalDirection(ref vD, ref vC, ref vOA);

            if (edge_flip_metric(ref n0, ref f1, flip_dot_tol) <= flip_dot_tol ||
                edge_flip_metric(ref n1, ref f1, flip_dot_tol) <= flip_dot_tol)
            {
                return(true);
            }
            return(false);
        }
        public void InitializeFromExisting(DMesh3 mesh, IEnumerable <int> added_v, IEnumerable <int> added_t)
        {
            initialize_buffers(mesh);
            bool has_groups = mesh.HasTriangleGroups;

            if (added_v != null)
            {
                foreach (int vid in added_v)
                {
                    Util.gDevAssert(mesh.IsVertex(vid));
                    append_vertex(mesh, vid);
                }
            }

            foreach (int tid in added_t)
            {
                Util.gDevAssert(mesh.IsTriangle(tid));

                Index3i tv  = mesh.GetTriangle(tid);
                Index4i tri = new Index4i(tv.a, tv.b, tv.c,
                                          has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID);
                AddedT.Add(tid);
                Triangles.Add(tri);
            }
        }
        public void Initialize(DMesh3 mesh, IEnumerable <int> triangles)
        {
            initialize_buffers(mesh);
            bool has_groups = mesh.HasTriangleGroups;


            foreach (int tid in triangles)
            {
                if (!mesh.IsTriangle(tid))
                {
                    continue;
                }

                Index3i tv = mesh.GetTriangle(tid);
                bool    va = save_vertex(mesh, tv.a);
                bool    vb = save_vertex(mesh, tv.b);
                bool    vc = save_vertex(mesh, tv.c);

                Index4i tri = new Index4i(tv.a, tv.b, tv.c,
                                          has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID);
                RemovedT.Add(tid);
                Triangles.Add(tri);

                MeshResult result = mesh.RemoveTriangle(tid, true, false);
                if (result != MeshResult.Ok)
                {
                    throw new Exception("RemoveTrianglesMeshChange.Initialize: exception in RemoveTriangle(" + tid.ToString() + "): " + result.ToString());
                }
                Util.gDevAssert(mesh.IsVertex(tv.a) == va && mesh.IsVertex(tv.b) == vb && mesh.IsVertex(tv.c) == vc);
            }
        }
        public void Apply(DMesh3 mesh)
        {
            int NV = AddedV.size;

            if (NV > 0)
            {
                NewVertexInfo vinfo = new NewVertexInfo(Positions[0]);
                mesh.BeginUnsafeVerticesInsert();
                for (int i = 0; i < NV; ++i)
                {
                    int vid = AddedV[i];
                    vinfo.v = Positions[i];
                    if (Normals != null)
                    {
                        vinfo.bHaveN = true; vinfo.n = Normals[i];
                    }
                    if (Colors != null)
                    {
                        vinfo.bHaveC = true; vinfo.c = Colors[i];
                    }
                    if (UVs != null)
                    {
                        vinfo.bHaveUV = true; vinfo.uv = UVs[i];
                    }
                    MeshResult result = mesh.InsertVertex(vid, ref vinfo, true);
                    if (result != MeshResult.Ok)
                    {
                        throw new Exception("AddTrianglesMeshChange.Revert: error in InsertVertex(" + vid.ToString() + "): " + result.ToString());
                    }
                }
                mesh.EndUnsafeVerticesInsert();
            }

            int NT = AddedT.size;

            if (NT > 0)
            {
                mesh.BeginUnsafeTrianglesInsert();
                for (int i = 0; i < NT; ++i)
                {
                    int        tid    = AddedT[i];
                    Index4i    tdata  = Triangles[i];
                    Index3i    tri    = new Index3i(tdata.a, tdata.b, tdata.c);
                    MeshResult result = mesh.InsertTriangle(tid, tri, tdata.d, true);
                    if (result != MeshResult.Ok)
                    {
                        throw new Exception("AddTrianglesMeshChange.Revert: error in InsertTriangle(" + tid.ToString() + "): " + result.ToString());
                    }
                }
                mesh.EndUnsafeTrianglesInsert();
            }

            if (OnApplyF != null)
            {
                OnApplyF(AddedV, AddedT);
            }
        }
Example #5
0
        /// <summary>
        /// Check if collapsing edge edgeID to point newv will flip normal of any attached face
        /// </summary>
        public static bool CheckIfCollapseCreatesFlip(DMesh3 mesh, int edgeID, Vector3d newv)
        {
            Index4i edge_info = mesh.GetEdge(edgeID);
            int     tc = edge_info.c, td = edge_info.d;

            for (int j = 0; j < 2; ++j)
            {
                int vid    = edge_info[j];
                int vother = edge_info[(j + 1) % 2];

                foreach (int tid in mesh.VtxTrianglesItr(vid))
                {
                    if (tid == tc || tid == td)
                    {
                        continue;
                    }

                    Index3i curt = mesh.GetTriangle(tid);
                    if (curt.a == vother || curt.b == vother || curt.c == vother)
                    {
                        return(true);                               // invalid nbrhood for collapse
                    }

                    Vector3d va   = mesh.GetVertex(curt.a);
                    Vector3d vb   = mesh.GetVertex(curt.b);
                    Vector3d vc   = mesh.GetVertex(curt.c);
                    Vector3d ncur = (vb - va).Cross(vc - va);
                    double   sign = 0;
                    if (curt.a == vid)
                    {
                        Vector3d nnew = (vb - newv).Cross(vc - newv);
                        sign = ncur.Dot(nnew);
                    }
                    else if (curt.b == vid)
                    {
                        Vector3d nnew = (newv - va).Cross(vc - va);
                        sign = ncur.Dot(nnew);
                    }
                    else if (curt.c == vid)
                    {
                        Vector3d nnew = (vb - va).Cross(newv - va);
                        sign = ncur.Dot(nnew);
                    }
                    else
                    {
                        throw new Exception("should never be here!");
                    }

                    if (sign <= 0.0)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Example #6
0
        /// <summary>
        /// For given edge, return it's triangles and the triangles that would
        /// be created if it was flipped (used in edge-flip optimizers)
        /// </summary>
        public static void GetEdgeFlipTris(DMesh3 mesh, int eID,
                                           out Index3i orig_t0, out Index3i orig_t1,
                                           out Index3i flip_t0, out Index3i flip_t1)
        {
            Index4i einfo = mesh.GetEdge(eID);
            Index2i ov = mesh.GetEdgeOpposingV(eID);
            int     a = einfo.a, b = einfo.b, c = ov.a, d = ov.b;
            int     t0 = einfo.c;
            Index3i tri_v = mesh.GetTriangle(t0);
            int     oa = a, ob = b;

            IndexUtil.orient_tri_edge(ref oa, ref ob, ref tri_v);
            orig_t0 = new Index3i(oa, ob, c);
            orig_t1 = new Index3i(ob, oa, d);
            flip_t0 = new Index3i(c, d, ob);
            flip_t1 = new Index3i(d, c, oa);
        }
        public void InitializeFromExisting(DMesh3 mesh, IEnumerable <int> remove_t)
        {
            initialize_buffers(mesh);
            bool has_groups = mesh.HasTriangleGroups;

            HashSet <int> triangles = new HashSet <int>(remove_t);
            HashSet <int> vertices  = new HashSet <int>();

            IndexUtil.TrianglesToVertices(mesh, remove_t, vertices);
            List <int> save_v = new List <int>();

            foreach (int vid in vertices)
            {
                bool all_contained = true;
                foreach (int tid in mesh.VtxTrianglesItr(vid))
                {
                    if (triangles.Contains(tid) == false)
                    {
                        all_contained = false;
                        break;
                    }
                }
                if (all_contained)
                {
                    save_v.Add(vid);
                }
            }

            foreach (int vid in save_v)
            {
                save_vertex(mesh, vid, true);
            }

            foreach (int tid in remove_t)
            {
                Util.gDevAssert(mesh.IsTriangle(tid));
                Index3i tv  = mesh.GetTriangle(tid);
                Index4i tri = new Index4i(tv.a, tv.b, tv.c,
                                          has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID);
                RemovedT.Add(tid);
                Triangles.Add(tri);
            }
        }
Example #8
0
 // actually write triangle line, in proper OBJ format
 static void write_quad(TextWriter writer, ref Index4i q, bool bNormals, bool bUVs, ref Index4i tuv)
 {
     if (bNormals == false && bUVs == false)
     {
         writer.WriteLine("f {0} {1} {2} {3}", q[0], q[1], q[2], q[3]);
     }
     else if (bNormals == true && bUVs == false)
     {
         writer.WriteLine("f {0}//{0} {1}//{1} {2}//{2} {3}//{3}", q[0], q[1], q[2], q[3]);
     }
     else if (bNormals == false && bUVs == true)
     {
         writer.WriteLine("f {0}/{4} {1}/{5} {2}/{6} {3}/{7}", q[0], q[1], q[2], q[3], tuv[0], tuv[1], tuv[2], tuv[3]);
     }
     else
     {
         writer.WriteLine("f {0}/{4}/{0} {1}/{5}/{1} {2}/{6}/{2} {3}/{7}/{3}", q[0], q[1], q[2], q[3], tuv[0], tuv[1], tuv[2], tuv[3]);
     }
 }
Example #9
0
        /// <summary>
        /// For given edge, return normals of it's two triangles, and normals
        /// of the triangles created if edge is flipped (used in edge-flip optimizers)
        /// </summary>
        public static void GetEdgeFlipNormals(DMesh3 mesh, int eID,
                                              out Vector3d n1, out Vector3d n2,
                                              out Vector3d on1, out Vector3d on2)
        {
            Index4i  einfo = mesh.GetEdge(eID);
            Index2i  ov = mesh.GetEdgeOpposingV(eID);
            int      a = einfo.a, b = einfo.b, c = ov.a, d = ov.b;
            int      t0 = einfo.c;
            Vector3d vC = mesh.GetVertex(c), vD = mesh.GetVertex(d);
            Index3i  tri_v = mesh.GetTriangle(t0);
            int      oa = a, ob = b;

            IndexUtil.orient_tri_edge(ref oa, ref ob, ref tri_v);
            Vector3d vOA = mesh.GetVertex(oa), vOB = mesh.GetVertex(ob);

            n1  = MathUtil.Normal(ref vOA, ref vOB, ref vC);
            n2  = MathUtil.Normal(ref vOB, ref vOA, ref vD);
            on1 = MathUtil.Normal(ref vC, ref vD, ref vOB);
            on2 = MathUtil.Normal(ref vD, ref vC, ref vOA);
        }
Example #10
0
 public int CompareTo(Index4i other)
 {
     if (a != other.a)
     {
         return(a < other.a ? -1 : 1);
     }
     else if (b != other.b)
     {
         return(b < other.b ? -1 : 1);
     }
     else if (c != other.c)
     {
         return(c < other.c ? -1 : 1);
     }
     else if (d != other.d)
     {
         return(d < other.d ? -1 : 1);
     }
     return(0);
 }
Example #11
0
 public void Set(Index4i o)
 {
     a = o[0]; b = o[1]; c = o[2]; d = o[3];
 }
Example #12
0
 public Index4i(Index4i copy)
 {
     a = copy.a; b = copy.b; c = copy.b; d = copy.d;
 }
Example #13
0
        public static bool Sort(ref int v0, ref int v1, ref int v2, ref int v3)
        {
            int  j0, j1, j2, j3;
            bool positive;

            if (v0 < v1)
            {
                if (v2 < v3)
                {
                    if (v1 < v2)
                    {
                        j0 = 0; j1 = 1; j2 = 2; j3 = 3; positive = true;
                    }
                    else if (v3 < v0)
                    {
                        j0 = 2; j1 = 3; j2 = 0; j3 = 1; positive = true;
                    }
                    else if (v2 < v0)
                    {
                        if (v3 < v1)
                        {
                            j0 = 2; j1 = 0; j2 = 3; j3 = 1; positive = false;
                        }
                        else
                        {
                            j0 = 2; j1 = 0; j2 = 1; j3 = 3; positive = true;
                        }
                    }
                    else
                    {
                        if (v3 < v1)
                        {
                            j0 = 0; j1 = 2; j2 = 3; j3 = 1; positive = true;
                        }
                        else
                        {
                            j0 = 0; j1 = 2; j2 = 1; j3 = 3; positive = false;
                        }
                    }
                }
                else
                {
                    if (v1 < v3)
                    {
                        j0 = 0; j1 = 1; j2 = 3; j3 = 2; positive = false;
                    }
                    else if (v2 < v0)
                    {
                        j0 = 3; j1 = 2; j2 = 0; j3 = 1; positive = false;
                    }
                    else if (v3 < v0)
                    {
                        if (v2 < v1)
                        {
                            j0 = 3; j1 = 0; j2 = 2; j3 = 1; positive = true;
                        }
                        else
                        {
                            j0 = 3; j1 = 0; j2 = 1; j3 = 2; positive = false;
                        }
                    }
                    else
                    {
                        if (v2 < v1)
                        {
                            j0 = 0; j1 = 3; j2 = 2; j3 = 1; positive = false;
                        }
                        else
                        {
                            j0 = 0; j1 = 3; j2 = 1; j3 = 2; positive = true;
                        }
                    }
                }
            }
            else
            {
                if (v2 < v3)
                {
                    if (v0 < v2)
                    {
                        j0 = 1; j1 = 0; j2 = 2; j3 = 3; positive = false;
                    }
                    else if (v3 < v1)
                    {
                        j0 = 2; j1 = 3; j2 = 1; j3 = 0; positive = false;
                    }
                    else if (v2 < v1)
                    {
                        if (v3 < v0)
                        {
                            j0 = 2; j1 = 1; j2 = 3; j3 = 0; positive = true;
                        }
                        else
                        {
                            j0 = 2; j1 = 1; j2 = 0; j3 = 3; positive = false;
                        }
                    }
                    else
                    {
                        if (v3 < v0)
                        {
                            j0 = 1; j1 = 2; j2 = 3; j3 = 0; positive = false;
                        }
                        else
                        {
                            j0 = 1; j1 = 2; j2 = 0; j3 = 3; positive = true;
                        }
                    }
                }
                else
                {
                    if (v0 < v3)
                    {
                        j0 = 1; j1 = 0; j2 = 3; j3 = 2; positive = true;
                    }
                    else if (v2 < v1)
                    {
                        j0 = 3; j1 = 2; j2 = 1; j3 = 0; positive = true;
                    }
                    else if (v3 < v1)
                    {
                        if (v2 < v0)
                        {
                            j0 = 3; j1 = 1; j2 = 2; j3 = 0; positive = false;
                        }
                        else
                        {
                            j0 = 3; j1 = 1; j2 = 0; j3 = 2; positive = true;
                        }
                    }
                    else
                    {
                        if (v2 < v0)
                        {
                            j0 = 1; j1 = 3; j2 = 2; j3 = 0; positive = true;
                        }
                        else
                        {
                            j0 = 1; j1 = 3; j2 = 0; j3 = 2; positive = false;
                        }
                    }
                }
            }

            Index4i value = new Index4i(v0, v1, v2, v3);

            v0 = value[j0];
            v1 = value[j1];
            v2 = value[j2];
            v3 = value[j3];
            return(positive);
        }
Example #14
0
        public MeshResult MergeEdges(int eKeep, int eDiscard, out MergeEdgesInfo merge_info)
        {
            merge_info = new MergeEdgesInfo();
            if (IsEdge(eKeep) == false || IsEdge(eDiscard) == false)
            {
                return(MeshResult.Failed_NotAnEdge);
            }

            Index4i edgeinfo_keep    = GetEdge(eKeep);
            Index4i edgeinfo_discard = GetEdge(eDiscard);

            if (edgeinfo_keep.d != InvalidID || edgeinfo_discard.d != InvalidID)
            {
                return(MeshResult.Failed_NotABoundaryEdge);
            }

            int a = edgeinfo_keep.a, b = edgeinfo_keep.b;
            int tab = edgeinfo_keep.c;
            int eab = eKeep;
            int c = edgeinfo_discard.a, d = edgeinfo_discard.b;
            int tcd = edgeinfo_discard.c;
            int ecd = eDiscard;

            // Need to correctly orient a,b and c,d and then check that
            // we will not join triangles with incompatible winding order
            // I can't see how to do this purely topologically.
            // So relying on closest-pairs testing.
            IndexUtil.orient_tri_edge(ref a, ref b, GetTriangle(tab));
            //int tcd_otherv = IndexUtil.orient_tri_edge_and_find_other_vtx(ref c, ref d, GetTriangle(tcd));
            IndexUtil.orient_tri_edge(ref c, ref d, GetTriangle(tcd));
            int      x = c; c = d; d = x;          // joinable bdry edges have opposing orientations, so flip to get ac and b/d correspondences
            Vector3d Va = GetVertex(a), Vb = GetVertex(b), Vc = GetVertex(c), Vd = GetVertex(d);

            if ((Va.DistanceSquared(Vc) + Vb.DistanceSquared(Vd)) >
                (Va.DistanceSquared(Vd) + Vb.DistanceSquared(Vc)))
            {
                return(MeshResult.Failed_SameOrientation);
            }

            // alternative that detects normal flip of triangle tcd. This is a more
            // robust geometric test, but fails if tri is degenerate...also more expensive
            //Vector3d otherv = GetVertex(tcd_otherv);
            //Vector3d Ncd = MathUtil.FastNormalDirection(GetVertex(c), GetVertex(d), otherv);
            //Vector3d Nab = MathUtil.FastNormalDirection(GetVertex(a), GetVertex(b), otherv);
            //if (Ncd.Dot(Nab) < 0)
            //return MeshResult.Failed_SameOrientation;

            merge_info.eKept    = eab;
            merge_info.eRemoved = ecd;

            // [TODO] this acts on each interior tri twice. could avoid using vtx-tri iterator?

            List <int> edges_a = vertex_edges[a];

            if (a != c)
            {
                // replace c w/ a in edges and tris connected to c, and move edges to a
                List <int> edges_c = vertex_edges[c];
                for (int i = 0; i < edges_c.Count; ++i)
                {
                    int eid = edges_c[i];
                    if (eid == eDiscard)
                    {
                        continue;
                    }
                    replace_edge_vertex(eid, c, a);
                    short rc = 0;
                    if (replace_tri_vertex(edges[4 * eid + 2], c, a) >= 0)
                    {
                        rc++;
                    }
                    if (edges[4 * eid + 3] != InvalidID)
                    {
                        if (replace_tri_vertex(edges[4 * eid + 3], c, a) >= 0)
                        {
                            rc++;
                        }
                    }
                    edges_a.Add(eid);
                    if (rc > 0)
                    {
                        vertices_refcount.increment(a, rc);
                        vertices_refcount.decrement(c, rc);
                    }
                }
                vertex_edges[c] = null;
                vertices_refcount.decrement(c);
                merge_info.vRemoved[0] = c;
            }
            else
            {
                edges_a.Remove(ecd);
                merge_info.vRemoved[0] = InvalidID;
            }
            merge_info.vKept[0] = a;

            List <int> edges_b = vertex_edges[b];

            if (d != b)
            {
                // replace d w/ b in edges and tris connected to d, and move edges to b
                List <int> edges_d = vertex_edges[d];
                for (int i = 0; i < edges_d.Count; ++i)
                {
                    int eid = edges_d[i];
                    if (eid == eDiscard)
                    {
                        continue;
                    }
                    replace_edge_vertex(eid, d, b);
                    short rc = 0;
                    if (replace_tri_vertex(edges[4 * eid + 2], d, b) >= 0)
                    {
                        rc++;
                    }
                    if (edges[4 * eid + 3] != InvalidID)
                    {
                        if (replace_tri_vertex(edges[4 * eid + 3], d, b) >= 0)
                        {
                            rc++;
                        }
                    }
                    edges_b.Add(eid);
                    if (rc > 0)
                    {
                        vertices_refcount.increment(b, rc);
                        vertices_refcount.decrement(d, rc);
                    }
                }
                vertex_edges[d] = null;
                vertices_refcount.decrement(d);
                merge_info.vRemoved[1] = d;
            }
            else
            {
                edges_b.Remove(ecd);
                merge_info.vRemoved[1] = InvalidID;
            }
            merge_info.vKept[1] = b;

            // replace edge cd with edge ab in triangle tcd
            replace_triangle_edge(tcd, ecd, eab);
            edges_refcount.decrement(ecd);

            // update edge-tri adjacency
            set_edge_triangles(eab, tab, tcd);

            // Once we merge ab to cd, there may be additional edges (now) connected
            // to either a or b that are connected to the same vertex on their 'other' side.
            // So we now have two boundary edges connecting the same two vertices - disaster!
            // We need to find and merge these edges.
            // Q: I don't think it is possible to have multiple such edge-pairs at a or b
            //    But I am not certain...is a bit tricky to handle because we modify edges_v...
            merge_info.eRemovedExtra = new Vector2i(InvalidID, InvalidID);
            merge_info.eKeptExtra    = merge_info.eRemovedExtra;
            for (int vi = 0; vi < 2; ++vi)
            {
                int v1 = a, v2 = c;                   // vertices of merged edge
                if (vi == 1)
                {
                    v1 = b; v2 = d;
                }
                if (v1 == v2)
                {
                    continue;
                }
                List <int> edges_v = vertex_edges[v1];
                int        Nedges  = edges_v.Count;
                bool       found   = false;
                // in this loop, we compare 'other' vert_1 and vert_2 of edges around v1.
                // problem case is when vert_1 == vert_2  (ie two edges w/ same other vtx).
                for (int i = 0; i < Nedges && found == false; ++i)
                {
                    int edge_1 = edges_v[i];
                    if (edge_is_boundary(edge_1) == false)
                    {
                        continue;
                    }
                    int vert_1 = edge_other_v(edge_1, v1);
                    for (int j = i + 1; j < Nedges; ++j)
                    {
                        int edge_2 = edges_v[j];
                        int vert_2 = edge_other_v(edge_2, v1);
                        if (vert_1 == vert_2 && edge_is_boundary(edge_2))                           // if ! boundary here, we are in deep trouble...
                        // replace edge_2 w/ edge_1 in tri, update edge and vtx-edge-nbr lists
                        {
                            int tri_1 = edges[4 * edge_1 + 2];
                            int tri_2 = edges[4 * edge_2 + 2];
                            replace_triangle_edge(tri_2, edge_2, edge_1);
                            set_edge_triangles(edge_1, tri_1, tri_2);
                            vertex_edges[v1].Remove(edge_2);
                            vertex_edges[vert_1].Remove(edge_2);
                            edges_refcount.decrement(edge_2);
                            merge_info.eRemovedExtra[vi] = edge_2;
                            merge_info.eKeptExtra[vi]    = edge_1;

                            //Nedges = edges_v.Count; // this code allows us to continue checking, ie in case we had
                            //i--;					  // multiple such edges. but I don't think it's possible.
                            found = true;                                                 // exit outer i loop
                            break;                                                        // exit inner j loop
                        }
                    }
                }
            }

            return(MeshResult.Ok);
        }
Example #15
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);
        }
Example #16
0
        /// <summary>
        /// Stitch two sets of boundary edges that are provided as unordered pairs of edges, by
        /// adding triangulated quads between each edge pair.
        /// If bAbortOnFailure==true and a failure is encountered during stitching, the triangles added up to that point are removed.
        /// If bAbortOnFailure==false, failures are ignored and the returned triangle list may contain invalid values!
        /// </summary>
        public virtual int[] StitchUnorderedEdges(List <Index2i> EdgePairs, int group_id, bool bAbortOnFailure, out bool stitch_incomplete)
        {
            int N = EdgePairs.Count;

            int[] new_tris = new int[N * 2];
            if (bAbortOnFailure == false)
            {
                for (int k = 0; k < new_tris.Length; ++k)
                {
                    new_tris[k] = DMesh3.InvalidID;
                }
            }
            stitch_incomplete = false;

            int i = 0;

            for (; i < N; ++i)
            {
                Index2i edges = EdgePairs[i];

                // look up and orient the first edge
                Index4i edge_a = Mesh.GetEdge(edges.a);
                if (edge_a.d != DMesh3.InvalidID)
                {
                    if (bAbortOnFailure)
                    {
                        goto operation_failed;
                    }
                    else
                    {
                        stitch_incomplete = true; continue;
                    }
                }
                Index3i edge_a_tri = Mesh.GetTriangle(edge_a.c);
                int     a = edge_a.a, b = edge_a.b;
                IndexUtil.orient_tri_edge(ref a, ref b, edge_a_tri);

                // look up and orient the second edge
                Index4i edge_b = Mesh.GetEdge(edges.b);
                if (edge_b.d != DMesh3.InvalidID)
                {
                    if (bAbortOnFailure)
                    {
                        goto operation_failed;
                    }
                    else
                    {
                        stitch_incomplete = true; continue;
                    }
                }
                Index3i edge_b_tri = Mesh.GetTriangle(edge_b.c);
                int     c = edge_b.a, d = edge_b.b;
                IndexUtil.orient_tri_edge(ref c, ref d, edge_b_tri);

                // swap second edge (right? should this be a parameter?)
                int tmp = c; c = d; d = tmp;

                var t1 = new Index3i(b, a, d);
                var t2 = new Index3i(a, c, d);

                int tid1 = Mesh.AppendTriangle(t1, group_id);
                int tid2 = Mesh.AppendTriangle(t2, group_id);

                if (tid1 < 0 || tid2 < 0)
                {
                    if (bAbortOnFailure)
                    {
                        goto operation_failed;
                    }
                    else
                    {
                        stitch_incomplete = true; continue;
                    }
                }

                new_tris[2 * i]     = tid1;
                new_tris[2 * i + 1] = tid2;
            }

            return(new_tris);

operation_failed:
            // remove what we added so far
            if (i > 0)
            {
                if (remove_triangles(new_tris, 2 * (i - 1)) == false)
                {
                    throw new Exception("MeshEditor.StitchLoop: failed to add all triangles, and also failed to back out changes.");
                }
            }
            return(null);
        }
Example #17
0
 public bool Equals(Index4i other)
 {
     return(a == other.a && b == other.b && c == other.c && d == other.d);
 }
Example #18
0
        /// <summary>
        /// Stitch two sets of boundary edges that are provided as unordered pairs of edges, by
        /// adding triangulated quads between each edge pair.
        /// If a failure is encountered during stitching, the triangles added up to that point are removed.
        /// </summary>
        public virtual int[] StitchUnorderedEdges(List <Index2i> EdgePairs, int group_id = -1)
        {
            int N = EdgePairs.Count;

            int[] new_tris = new int[N * 2];

            int i = 0;

            for (; i < N; ++i)
            {
                Index2i edges = EdgePairs[i];

                // look up and orient the first edge
                Index4i edge_a = Mesh.GetEdge(edges.a);
                if (edge_a.d != DMesh3.InvalidID)
                {
                    goto operation_failed;
                }
                Index3i edge_a_tri = Mesh.GetTriangle(edge_a.c);
                int     a = edge_a.a, b = edge_a.b;
                IndexUtil.orient_tri_edge(ref a, ref b, edge_a_tri);

                // look up and orient the second edge
                Index4i edge_b = Mesh.GetEdge(edges.b);
                if (edge_b.d != DMesh3.InvalidID)
                {
                    goto operation_failed;
                }
                Index3i edge_b_tri = Mesh.GetTriangle(edge_b.c);
                int     c = edge_b.a, d = edge_b.b;
                IndexUtil.orient_tri_edge(ref c, ref d, edge_b_tri);

                // swap second edge (right? should this be a parameter?)
                int tmp = c; c = d; d = tmp;

                Index3i t1 = new Index3i(b, a, d);
                Index3i t2 = new Index3i(a, c, d);

                int tid1 = Mesh.AppendTriangle(t1, group_id);
                int tid2 = Mesh.AppendTriangle(t2, group_id);

                if (tid1 == DMesh3.InvalidID || tid2 == DMesh3.InvalidID)
                {
                    goto operation_failed;
                }

                new_tris[2 * i]     = tid1;
                new_tris[2 * i + 1] = tid2;
            }

            return(new_tris);

operation_failed:
            // remove what we added so far
            if (i > 0)
            {
                if (remove_triangles(new_tris, 2 * (i - 1)) == false)
                {
                    throw new Exception("MeshConstructor.StitchLoop: failed to add all triangles, and also failed to back out changes.");
                }
            }
            return(null);
        }
        // Walk along edge loop and collapse to inserted curve vertices.
        EdgeLoop simplify(EdgeLoop loop)
        {
            HashSet <int> curve_verts = new HashSet <int>(CurveVertices);

            List <int> remaining_edges = new List <int>();

            for (int li = 0; li < loop.EdgeCount; ++li)
            {
                int     eid = loop.Edges[li];
                Index2i ev  = Mesh.GetEdgeV(eid);

                // cannot collapse edge between two "original" polygon verts (ie created by face pokes)
                if (curve_verts.Contains(ev.a) && curve_verts.Contains(ev.b))
                {
                    remaining_edges.Add(eid);
                    continue;
                }

                // if we have an original vert, we need to keep it (and its position!)
                int      keep = ev.a, discard = ev.b;
                Vector3d set_to = Vector3d.Zero;
                if (curve_verts.Contains(ev.b))
                {
                    keep    = ev.b;
                    discard = ev.a;
                    set_to  = Mesh.GetVertex(ev.b);
                }
                else if (curve_verts.Contains(ev.a))
                {
                    set_to = Mesh.GetVertex(ev.a);
                }
                else
                {
                    set_to = 0.5 * (Mesh.GetVertex(ev.a) + Mesh.GetVertex(ev.b));
                }

                // make sure we are not going to flip any normals
                // [OPTIMIZATION] May be possible to do this more efficiently because we know we are in
                //   2D and each tri should have same cw/ccw orientation. But we don't quite "know" we
                //   are in 2D here, as CollapseEdge function is operating on the mesh coordinates...
                if (MeshUtil.CheckIfCollapseCreatesFlip(Mesh, eid, set_to))
                {
                    remaining_edges.Add(eid);
                    continue;
                }

                // cannot collapse if the 'other' edges we would discard are OnCutEdges. This would
                // result in loop potentially being broken. bad!
                Index4i einfo = Mesh.GetEdge(eid);
                int     c     = IndexUtil.find_tri_other_vtx(keep, discard, Mesh.GetTriangle(einfo.c));
                int     d     = IndexUtil.find_tri_other_vtx(keep, discard, Mesh.GetTriangle(einfo.d));
                int     ec    = Mesh.FindEdge(discard, c);
                int     ed    = Mesh.FindEdge(discard, d);
                if (OnCutEdges.Contains(ec) || OnCutEdges.Contains(ed))
                {
                    remaining_edges.Add(eid);
                    continue;
                }

                // do collapse and update internal data structures
                DMesh3.EdgeCollapseInfo collapse;
                MeshResult result = Mesh.CollapseEdge(keep, discard, out collapse);
                if (result == MeshResult.Ok)
                {
                    Mesh.SetVertex(collapse.vKept, set_to);
                    OnCutEdges.Remove(collapse.eCollapsed);
                }
                else
                {
                    remaining_edges.Add(eid);
                }
            }

            return(EdgeLoop.FromEdges(Mesh, remaining_edges));
        }
Example #20
0
        public static IOWriteResult WriteOBJ(SimpleQuadMesh mesh, string sPath, WriteOptions options)
        {
            StreamWriter writer = new StreamWriter(sPath);

            if (writer.BaseStream == null)
            {
                return(new IOWriteResult(IOCode.FileAccessError, "Could not open file " + sPath + " for writing"));
            }

            bool bVtxColors = options.bPerVertexColors && mesh.HasVertexColors;
            bool bNormals   = options.bPerVertexNormals && mesh.HasVertexNormals;

            // use separate UV set if we have it, otherwise write per-vertex UVs if we have those
            bool bVtxUVs = options.bPerVertexUVs && mesh.HasVertexUVs;

            if (mesh.UVs != null)
            {
                bVtxUVs = false;
            }

            int[] mapV = new int[mesh.MaxVertexID];

            int nAccumCountV = 1;       // OBJ indices always start at 1

            // write vertices for this mesh
            foreach (int vi in mesh.VertexIndices())
            {
                mapV[vi] = nAccumCountV++;
                Vector3d v = mesh.GetVertex(vi);
                if (bVtxColors)
                {
                    Vector3d c = mesh.GetVertexColor(vi);
                    writer.WriteLine("v {0} {1} {2} {3:F8} {4:F8} {5:F8}", v[0], v[1], v[2], c[0], c[1], c[2]);
                }
                else
                {
                    writer.WriteLine("v {0} {1} {2}", v[0], v[1], v[2]);
                }

                if (bNormals)
                {
                    Vector3d n = mesh.GetVertexNormal(vi);
                    writer.WriteLine("vn {0:F10} {1:F10} {2:F10}", n[0], n[1], n[2]);
                }

                if (bVtxUVs)
                {
                    Vector2f uv = mesh.GetVertexUV(vi);
                    writer.WriteLine("vt {0:F10} {1:F10}", uv.x, uv.y);
                }
            }

            foreach (int ti in mesh.QuadIndices())
            {
                Index4i q = mesh.GetQuad(ti);
                q[0] = mapV[q[0]];
                q[1] = mapV[q[1]];
                q[2] = mapV[q[2]];
                q[3] = mapV[q[3]];
                write_quad(writer, ref q, bNormals, bVtxUVs, ref q);
            }

            writer.Close();

            return(IOWriteResult.Ok);
        }