Esempio n. 1
0
        /// <summary>
        /// Add all triangles in vertex one-rings of current selection to set.
        /// On a large mesh this is quite expensive as we don't know the boundary,
        /// so we have to iterate over all triangles.
        ///
        /// Return false from FilterF to prevent triangles from being included.
        /// </summary>
        public void ExpandToOneRingNeighbours(Func <int, bool> FilterF = null)
        {
            temp.Clear();

            foreach (int tid in Selected)
            {
                Index3i tri_v = Mesh.GetTriangle(tid);
                for (int j = 0; j < 3; ++j)
                {
                    int vid = tri_v[j];
                    foreach (int nbr_t in Mesh.VtxTrianglesItr(vid))
                    {
                        if (FilterF != null && FilterF(nbr_t) == false)
                        {
                            continue;
                        }
                        if (IsSelected(nbr_t) == false)
                        {
                            temp.Add(nbr_t);
                        }
                    }
                }
            }

            for (int i = 0; i < temp.Count; ++i)
            {
                add(temp[i]);
            }
        }
 public void SelectTriangleVertices(int[] triangles)
 {
     for (int i = 0; i < triangles.Length; ++i)
     {
         Index3i tri = Mesh.GetTriangle(triangles[i]);
         add(tri.a); add(tri.b); add(tri.c);
     }
 }
Esempio n. 3
0
        // accumulate triangle counts and track each box-parent index.
        // also checks that triangles are contained in boxes
        private void test_coverage(int[] tri_counts, int[] parent_indices, int iBox)
        {
            int idx = box_to_index[iBox];

            debug_check_child_tris_in_box(iBox);

            if (idx < triangles_end)
            {
                // triange-list case, array is [N t1 t2 ... tN]
                int n = index_list[idx];
                AxisAlignedBox3f box = get_box(iBox);
                for (int i = 1; i <= n; ++i)
                {
                    int ti = index_list[idx + i];
                    tri_counts[ti]++;

                    Index3i tv = mesh.GetTriangle(ti);
                    for (int j = 0; j < 3; ++j)
                    {
                        Vector3f v = (Vector3f)mesh.GetVertex(tv[j]);
                        if (!box.Contains(v))
                        {
                            Util.gBreakToDebugger();
                        }
                    }
                }
            }
            else
            {
                int i0 = index_list[idx];
                if (i0 < 0)
                {
                    // negative index means we only have one 'child' box to descend into
                    i0 = (-i0) - 1;
                    parent_indices[i0] = iBox;
                    test_coverage(tri_counts, parent_indices, i0);
                }
                else
                {
                    // positive index, two sequential child box indices to descend into
                    i0 = i0 - 1;
                    parent_indices[i0] = iBox;
                    test_coverage(tri_counts, parent_indices, i0);
                    int i1 = index_list[idx + 1];
                    i1 = i1 - 1;
                    parent_indices[i1] = iBox;
                    test_coverage(tri_counts, parent_indices, i1);
                }
            }
        }
Esempio n. 4
0
        // [RMS] estimate can be zero
        void compute(IEnumerable <int> triangles, int tri_count_est)
        {
            int est_verts = tri_count_est / 2;

            SubMesh = new DMesh3(BaseMesh.Components & WantComponents);

            BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts);
            BaseToSubV   = new IndexMap(BaseMesh.MaxVertexID, est_verts);
            SubToBaseV   = new DVector <int>();

            if (ComputeTriMaps)
            {
                BaseToSubT = new IndexMap(BaseMesh.MaxTriangleID, tri_count_est);
                SubToBaseT = new DVector <int>();
            }

            foreach (int tid in triangles)
            {
                if (!BaseMesh.IsTriangle(tid))
                {
                    throw new Exception("DSubmesh3.compute: triangle " + tid + " does not exist in BaseMesh!");
                }

                Index3i base_t = BaseMesh.GetTriangle(tid);
                Index3i new_t  = Index3i.Zero;
                int     gid    = BaseMesh.GetTriangleGroup(tid);

                for (int j = 0; j < 3; ++j)
                {
                    int base_v = base_t[j];
                    int sub_v  = -1;
                    if (BaseSubmeshV[base_v] == false)
                    {
                        sub_v = SubMesh.AppendVertex(BaseMesh, base_v);
                        BaseSubmeshV[base_v] = true;
                        BaseToSubV[base_v]   = sub_v;
                        SubToBaseV.insert(base_v, sub_v);
                    }
                    else
                    {
                        sub_v = BaseToSubV[base_v];
                    }

                    new_t[j] = sub_v;
                }

                if (OverrideGroupID >= 0)
                {
                    gid = OverrideGroupID;
                }

                int sub_tid = SubMesh.AppendTriangle(new_t, gid);

                if (ComputeTriMaps)
                {
                    BaseToSubT[tid] = sub_tid;
                    SubToBaseT.insert(tid, sub_tid);
                }
            }
        }
        /// <summary>
        /// Compute volume and surface area of triangles of mesh.
        /// Return value is (volume,area)
        /// Note that if triangles don't define closed region, volume is probably nonsense...
        /// </summary>
        public static Vector2d VolumeArea(DMesh3 mesh, IEnumerable <int> triangles,
                                          Func <int, Vector3d> getVertexF)
        {
            double mass_integral = 0.0;
            double area_sum      = 0;

            foreach (int tid in triangles)
            {
                Index3i tri = mesh.GetTriangle(tid);
                // Get vertices of triangle i.
                Vector3d v0 = getVertexF(tri.a);
                Vector3d v1 = getVertexF(tri.b);
                Vector3d v2 = getVertexF(tri.c);

                // Get cross product of edges and (un-normalized) normal vector.
                Vector3d V1mV0 = v1 - v0;
                Vector3d V2mV0 = v2 - v0;
                Vector3d N     = V1mV0.Cross(V2mV0);

                area_sum += 0.5 * N.Length;

                double tmp0 = v0.x + v1.x;
                double f1x  = tmp0 + v2.x;
                mass_integral += N.x * f1x;
            }

            return(new Vector2d(mass_integral * (1.0 / 6.0), area_sum));
        }
        // convert vertex selection to face selection. Require at least minCount verts of
        // tri to be selected (valid values are 1,2,3)
        public MeshFaceSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 3) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 3);

            foreach (int tid in mesh.TriangleIndices())
            {
                Index3i tri = mesh.GetTriangle(tid);

                if (minCount == 1)
                {
                    if (convertV.IsSelected(tri.a) || convertV.IsSelected(tri.b) || convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else if (minCount == 3)
                {
                    if (convertV.IsSelected(tri.a) && convertV.IsSelected(tri.b) && convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else
                {
                    int n = (convertV.IsSelected(tri.a) ? 1 : 0) +
                            (convertV.IsSelected(tri.b) ? 1 : 0) +
                            (convertV.IsSelected(tri.c) ? 1 : 0);
                    if (n >= minCount)
                    {
                        add(tid);
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// find base-mesh interior vertices of region (ie does not include region boundary vertices)
        /// </summary>
        public HashSet <int> CurrentBaseInteriorVertices()
        {
            var          verts   = new HashSet <int>();
            IndexHashSet borderv = Region.BaseBorderV;

            foreach (int tid in cur_base_tris)
            {
                Index3i tv = BaseMesh.GetTriangle(tid);
                if (borderv[tv.a] == false)
                {
                    verts.Add(tv.a);
                }

                if (borderv[tv.b] == false)
                {
                    verts.Add(tv.b);
                }

                if (borderv[tv.c] == false)
                {
                    verts.Add(tv.c);
                }
            }
            return(verts);
        }
        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);
            }
        }
Esempio n. 9
0
        override public MeshGenerator Generate()
        {
            MeshInsertPolygon insert;
            DMesh3            base_mesh = ComputeResult(out insert);

            DMesh3 compact = new DMesh3(base_mesh, true);

            int NV = compact.VertexCount;

            vertices = new VectorArray3d(NV);
            uv       = new VectorArray2f(NV);
            normals  = new VectorArray3f(NV);
            for (int vi = 0; vi < NV; ++vi)
            {
                vertices[vi] = compact.GetVertex(vi);
                uv[vi]       = compact.GetVertexUV(vi);
                normals[vi]  = FixedNormal;
            }

            int NT = compact.TriangleCount;

            triangles = new IndexArray3i(NT);
            for (int ti = 0; ti < NT; ++ti)
            {
                triangles[ti] = compact.GetTriangle(ti);
            }

            return(this);
        }
Esempio n. 10
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 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);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// check if edge collapse will create a face-normal flip.
        /// Also checks if collapse would violate link condition, since
        /// we are iterating over one-ring anyway.
        ///
        /// This only checks one-ring of vid, so you have to call it twice,
        /// with vid and vother reversed, to check both one-rings
        /// </summary>
        protected bool collapse_creates_flip_or_invalid(int vid, int vother, ref Vector3d newv, int tc, int td)
        {
            Vector3d va = Vector3d.Zero, vb = Vector3d.Zero, vc = Vector3d.Zero;

            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
                }

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

                if (sign <= edge_flip_tol)
                {
                    return(true);
                }
            }
            return(false);
        }
Esempio n. 13
0
 public static void TrianglesToVertices(DMesh3 mesh, HashSet <int> triangles, HashSet <int> vertices)
 {
     foreach (int tid in triangles)
     {
         Index3i tv = mesh.GetTriangle(tid);
         vertices.Add(tv.a); vertices.Add(tv.b); vertices.Add(tv.c);
     }
 }
Esempio n. 14
0
 // convert face selection to vertex selection.
 public MeshVertexSelection(DMesh3 mesh, MeshFaceSelection convertT) : this(mesh)
 {
     foreach (int tid in convertT)
     {
         Index3i tv = mesh.GetTriangle(tid);
         add(tv.a); add(tv.b); add(tv.c);
     }
 }
        // return same indices as GetEdgeV, but oriented based on attached triangle
        Index2i get_oriented_edgev(int eID, int tid_in, int tid_out)
        {
            Index2i edgev = Mesh.GetEdgeV(eID);
            int     a = edgev.a, b = edgev.b;
            Index3i tri = Mesh.GetTriangle(tid_in);
            int     ai  = IndexUtil.find_edge_index_in_tri(a, b, ref tri);

            return(new Index2i(tri[ai], tri[(ai + 1) % 3]));
        }
        void spatial_add_triangle(int tid)
        {
            if (triSpatial == null)
            {
                return;
            }
            Index3i  tv = Mesh.GetTriangle(tid);
            Vector2d a = PointF(tv.a), b = PointF(tv.b), c = PointF(tv.c);

            triSpatial.InsertTriangleUnsafe(tid, ref a, ref b, ref c);
        }
Esempio n. 17
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);
        }
Esempio n. 18
0
        // (sequentially) find each triangle that path point lies in, and insert a vertex for
        // that point into mesh.
        void insert_corners()
        {
            PrimalQuery2d query = new PrimalQuery2d(PointF);

            // [TODO] can do everythnig up to PokeTriangle in parallel,
            // except if we are poking same tri w/ multiple points!

            CurveVertices = new int[Curve.VertexCount];
            for (int i = 0; i < Curve.VertexCount; ++i)
            {
                Vector2d vInsert  = Curve[i];
                bool     inserted = false;

                foreach (int tid in Mesh.TriangleIndices())
                {
                    Index3i tv = Mesh.GetTriangle(tid);
                    // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation
                    //   (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation)
                    //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c);
                    int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c);
                    if (query_result == -1 || query_result == 0)
                    {
                        Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c));
                        int      vid  = insert_corner_from_bary(i, tid, bary);
                        if (vid > 0)        // this should be always happening..
                        {
                            CurveVertices[i] = vid;
                            inserted         = true;

                            //Util.WriteDebugMesh(Mesh, string.Format("C:\\git\\geometry3SharpDemos\\geometry3Test\\test_output\\after_insert_corner_{0}.obj", i));
                            break;
                        }
                    }
                }

                if (inserted == false)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex "
                                        + i.ToString() + " is not inside or on any mesh triangle!");
                }
            }
        }
Esempio n. 19
0
        /// <summary>
        /// computes sum of opening-angles in triangles around vid, minus 2pi.
        /// This is zero on flat areas.
        /// </summary>
        public static double DiscreteGaussCurvature(DMesh3 mesh, int vid)
        {
            double angle_sum = 0;

            foreach (int tid in mesh.VtxTrianglesItr(vid))
            {
                Index3i et  = mesh.GetTriangle(tid);
                int     idx = IndexUtil.find_tri_index(vid, ref et);
                angle_sum += mesh.GetTriInternalAngleR(tid, idx);
            }
            return(angle_sum - MathUtil.TwoPI);
        }
Esempio n. 20
0
        // create Component from triangles
        Component extract_submesh(int submesh_index, int[] subt, int Nt, int[] mapToCur, int[] subv,
                                  out Index2i mapRange, out int max_subv)
        {
            int subvi = 0;

            Component C = new Component();

            C.id        = submesh_index;
            C.triangles = new int[Nt * 3];
            C.tri_count = Nt;

            mapRange = new Index2i(int.MaxValue, int.MinValue);

            // construct list of triangles and vertex map
            for (int ti = 0; ti < Nt; ++ti)
            {
                int     tid = subt[ti];
                Index3i tri = mesh.GetTriangle(tid);
                for (int j = 0; j < 3; ++j)
                {
                    int vid = tri[j];
                    if (mapToCur[vid] == 0)
                    {
                        mapToCur[vid] = (subvi + 1);
                        subv[subvi]   = vid;

                        if (vid < mapRange.a)
                        {
                            mapRange.a = vid;
                        }
                        else if (vid > mapRange.b)
                        {
                            mapRange.b = vid;
                        }

                        if (TrackVertexMapping)
                        {
                            add_submesh_mapv(vid, C.id, subvi);
                        }

                        subvi++;
                    }
                    C.triangles[3 * ti + j] = mapToCur[vid] - 1;
                }
            }

            C.source_vertices = new int[subvi];
            Array.Copy(subv, C.source_vertices, subvi);
            max_subv = subvi;

            return(C);
        }
Esempio n. 21
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);
        }
Esempio n. 22
0
        // from http://www.geometry.caltech.edu/pubs/DMSB_III.pdf
        public static double VoronoiArea(DMesh3 mesh, int v_i)
        {
            double   areaSum = 0;
            Vector3d Vi      = mesh.GetVertex(v_i);

            foreach (int tid in mesh.VtxTrianglesItr(v_i))
            {
                Index3i  t  = mesh.GetTriangle(tid);
                int      ti = (t[0] == v_i) ? 0 : ((t[1] == v_i) ? 1 : 2);
                Vector3d Vj = mesh.GetVertex(t[(ti + 1) % 3]);
                Vector3d Vk = mesh.GetVertex(t[(ti + 2) % 3]);

                if (MathUtil.IsObtuse(Vi, Vj, Vk))
                {
                    Vector3d Vij = Vj - Vi;
                    Vector3d Vik = Vk - Vi;
                    Vij.Normalize(); Vik.Normalize();
                    double areaT = 0.5 * Vij.Cross(Vik).Length;
                    if (Vector3d.AngleR(Vij, Vik) > MathUtil.HalfPI)
                    {
                        areaSum += (areaT * 0.5);                           // obtuse at v_i
                    }
                    else
                    {
                        areaSum += (areaT * 0.25);                              // not obtuse
                    }
                }
                else
                {
                    // voronoi area
                    Vector3d Vji     = Vi - Vj;
                    double   dist_ji = Vji.Normalize();
                    Vector3d Vki     = Vi - Vk;
                    double   dist_ki = Vki.Normalize();
                    Vector3d Vkj     = (Vj - Vk).Normalized;

                    double cot_alpha_ij = MathUtil.VectorCot(Vki, Vkj);
                    double cot_alpha_ik = MathUtil.VectorCot(Vji, -Vkj);
                    areaSum += dist_ji * dist_ji * cot_alpha_ij * 0.125;
                    areaSum += dist_ki * dist_ki * cot_alpha_ik * 0.125;
                }
            }
            return(areaSum);
        }
Esempio n. 23
0
 static void check_neighbour(DMesh3 mesh,
                             DenseGrid3f phi, DenseGrid3i closest_tri,
                             Vector3f gx, int i0, int j0, int k0, int i1, int j1, int k1)
 {
     if (closest_tri[i1, j1, k1] >= 0)
     {
         Index3i  tri = mesh.GetTriangle(closest_tri[i1, j1, k1]);
         int      p = tri.a, q = tri.b, r = tri.c;
         Vector3f xp = (Vector3f)mesh.GetVertex(p);
         Vector3f xq = (Vector3f)mesh.GetVertex(q);
         Vector3f xr = (Vector3f)mesh.GetVertex(r);
         float    d  = point_triangle_distance(gx, xp, xq, xr);
         if (d < phi[i0, j0, k0])
         {
             phi[i0, j0, k0]         = d;
             closest_tri[i0, j0, k0] = closest_tri[i1, j1, k1];
         }
     }
 }
Esempio n. 24
0
        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);
            }
        }
Esempio n. 25
0
        public void CompactCopy(DMesh3 copy, bool bNormals = true, bool bColors = true, bool bUVs = true)
        {
            if (copy.IsCompact)
            {
                Copy(copy, bNormals, bColors, bUVs);
                return;
            }

            vertices           = new DVector <double>();
            vertex_edges       = new DVector <List <int> >();
            vertices_refcount  = new RefCountVector();
            triangles          = new DVector <int>();
            triangle_edges     = new DVector <int>();
            triangles_refcount = new RefCountVector();
            edges          = new DVector <int>();
            edges_refcount = new RefCountVector();

            normals = (bNormals && copy.normals != null) ? new DVector <float>() : null;
            colors  = (bColors && copy.colors != null) ? new DVector <float>() : null;
            uv      = (bUVs && copy.uv != null) ? new DVector <float>() : null;

            // [TODO] if we knew some of these were dense we could copy directly...

            NewVertexInfo vinfo = new NewVertexInfo();

            int[] mapV = new int[copy.MaxVertexID];
            foreach (int vid in copy.vertices_refcount)
            {
                copy.GetVertex(vid, ref vinfo, bNormals, bColors, bUVs);
                mapV[vid] = AppendVertex(vinfo);
            }

            // [TODO] would be much faster to explicitly copy triangle & edge data structures!!

            foreach (int tid in copy.triangles_refcount)
            {
                Index3i t = copy.GetTriangle(tid);
                t.a = mapV[t.a]; t.b = mapV[t.b]; t.c = mapV[t.c];
                int g = (copy.HasTriangleGroups) ? copy.GetTriangleGroup(tid) : InvalidID;
                AppendTriangle(t, g);
            }
        }
Esempio n. 26
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);
        }
Esempio n. 27
0
        // Modes: 0: centroids, 1: any vertex, 2: 2 vertices, 3: all vertices
        // ContainF should return true if 3D position is in set (eg inside box, etc)
        // If mode = 0, will be called with (centroid, tri_idx)
        // If mode = 1/2/3, will be called with (vtx_pos, vtx_idx)
        // AddF is called with triangle IDs that are in set
        public static void TrianglesContained(DMesh3 mesh, Func <Vector3d, int, bool> ContainF, Action <int> AddF, int nMode = 0)
        {
            BitArray inV = null;

            if (nMode != 0)
            {
                inV = new BitArray(mesh.MaxVertexID);
                foreach (int vid in mesh.VertexIndices())
                {
                    if (ContainF(mesh.GetVertex(vid), vid))
                    {
                        inV[vid] = true;
                    }
                }
            }

            foreach (int tid in mesh.TriangleIndices())
            {
                Index3i tri = mesh.GetTriangle(tid);

                bool bIn = false;
                if (nMode == 0)
                {
                    if (ContainF(mesh.GetTriCentroid(tid), tid))
                    {
                        bIn = true;
                    }
                }
                else
                {
                    int countIn = (inV[tri.a] ? 1 : 0) + (inV[tri.b] ? 1 : 0) + (inV[tri.c] ? 1 : 0);
                    bIn = (countIn >= nMode);
                }

                if (bIn)
                {
                    AddF(tid);
                }
            }
        }
Esempio n. 28
0
        void compute(IEnumerable <int> triangles, int tri_count)
        {
            int est_verts = tri_count / 2;

            SubMesh = new DMesh3(BaseMesh.Components & WantComponents);

            BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts);
            BaseToSubV   = new IndexMap(BaseMesh.MaxVertexID, est_verts);
            SubToBaseV   = new DVector <int>();

            foreach (int ti in triangles)
            {
                Index3i base_t = BaseMesh.GetTriangle(ti);
                Index3i new_t  = Index3i.Zero;
                int     gid    = BaseMesh.GetTriangleGroup(ti);

                for (int j = 0; j < 3; ++j)
                {
                    int base_v = base_t[j];
                    int sub_v  = -1;
                    if (BaseSubmeshV[base_v] == false)
                    {
                        sub_v = SubMesh.AppendVertex(BaseMesh, base_v);
                        BaseSubmeshV[base_v] = true;
                        BaseToSubV[base_v]   = sub_v;
                        SubToBaseV.insert(base_v, sub_v);
                    }
                    else
                    {
                        sub_v = BaseToSubV[base_v];
                    }
                    new_t[j] = sub_v;
                }

                SubMesh.AppendTriangle(new_t, gid);
            }
        }
Esempio n. 29
0
        /// <summary>
        /// 1) Find intersection segments
        /// 2) sort onto existing input mesh vtx/edge/face
        /// </summary>
        void find_segments()
        {
            Dictionary <Vector3d, SegmentVtx> SegVtxMap = new Dictionary <Vector3d, SegmentVtx>();

            // find intersection segments
            // TODO: intersection polygons
            // TODO: do we need to care about intersection vertices?
            DMeshAABBTree3 targetSpatial = new DMeshAABBTree3(Target, true);
            DMeshAABBTree3 cutSpatial    = new DMeshAABBTree3(CutMesh, true);
            var            intersections = targetSpatial.FindAllIntersections(cutSpatial);

            // for each segment, for each vtx, determine if it is
            // at an existing vertex, on-edge, or in-face
            Segments = new IntersectSegment[intersections.Segments.Count];
            for (int i = 0; i < Segments.Length; ++i)
            {
                var              isect  = intersections.Segments[i];
                Vector3dTuple2   points = new Vector3dTuple2(isect.point0, isect.point1);
                IntersectSegment iseg   = new IntersectSegment()
                {
                    base_tid = isect.t0
                };
                Segments[i] = iseg;
                for (int j = 0; j < 2; ++j)
                {
                    Vector3d v = points[j];

                    // if this exact vtx coord has been seen, use same vtx
                    SegmentVtx sv;
                    if (SegVtxMap.TryGetValue(v, out sv))
                    {
                        iseg[j] = sv;
                        continue;
                    }
                    sv = new SegmentVtx()
                    {
                        v = v
                    };
                    SegVertices.Add(sv);
                    SegVtxMap[v] = sv;
                    iseg[j]      = sv;

                    // this vtx is tol-equal to input mesh vtx
                    int existing_v = find_existing_vertex(isect.point0);
                    if (existing_v >= 0)
                    {
                        sv.initial_type           = sv.type = 0;
                        sv.elem_id                = existing_v;
                        sv.vtx_id                 = existing_v;
                        VIDToSegVtxMap[sv.vtx_id] = sv;
                        continue;
                    }

                    Triangle3d tri = new Triangle3d();
                    Target.GetTriVertices(isect.t0, ref tri.V0, ref tri.V1, ref tri.V2);
                    Index3i tv = Target.GetTriangle(isect.t0);

                    // this vtx is tol-on input mesh edge
                    int on_edge_i = on_edge(ref tri, ref v);
                    if (on_edge_i >= 0)
                    {
                        sv.initial_type = sv.type = 1;
                        sv.elem_id      = Target.FindEdge(tv[on_edge_i], tv[(on_edge_i + 1) % 3]);
                        Util.gDevAssert(sv.elem_id != DMesh3.InvalidID);
                        add_edge_vtx(sv.elem_id, sv);
                        continue;
                    }

                    // otherwise contained in input mesh face
                    sv.initial_type = sv.type = 2;
                    sv.elem_id      = isect.t0;
                    add_face_vtx(sv.elem_id, sv);
                }
            }
        }
Esempio n. 30
0
        protected virtual ProcessResult CollapseEdge(int edgeID, Vector3d vNewPos, out int collapseToV)
        {
            collapseToV = DMesh3.InvalidID;
            RuntimeDebugCheck(edgeID);

            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }
            if (constraint.CanCollapse == false)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }


            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }
            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            // look up 'other' verts c (from t0) and d (from t1, if it exists)
            Index3i T0tv         = mesh.GetTriangle(t0);
            int     c            = IndexUtil.find_tri_other_vtx(a, b, T0tv);
            Index3i T1tv         = (bIsBoundaryEdge) ? DMesh3.InvalidTriangle : mesh.GetTriangle(t1);
            int     d            = (bIsBoundaryEdge) ? DMesh3.InvalidID : IndexUtil.find_tri_other_vtx(a, b, T1tv);

            Vector3d vA           = mesh.GetVertex(a);
            Vector3d vB           = mesh.GetVertex(b);
            double   edge_len_sqr = (vA - vB).LengthSquared;

            if (edge_len_sqr > MinEdgeLength * MinEdgeLength)
            {
                return(ProcessResult.Ignored_EdgeTooLong);
            }

            begin_collapse();

            // check if we should collapse, and also find which vertex we should collapse to,
            // in cases where we have constraints/etc
            int  collapse_to  = -1;
            bool bCanCollapse = can_collapse_constraints(edgeID, a, b, c, d, t0, t1, out collapse_to);

            if (bCanCollapse == false)
            {
                return(ProcessResult.Ignored_Constrained);
            }

            // if we have a boundary, we want to collapse to boundary
            if (PreserveBoundary && HaveBoundary)
            {
                if (collapse_to != -1)
                {
                    if ((IsBoundaryV(b) && collapse_to != b) ||
                        (IsBoundaryV(a) && collapse_to != a))
                    {
                        return(ProcessResult.Ignored_Constrained);
                    }
                }
                if (IsBoundaryV(b))
                {
                    collapse_to = b;
                }
                else if (IsBoundaryV(a))
                {
                    collapse_to = a;
                }
            }

            // optimization: if edge cd exists, we cannot collapse or flip. look that up here?
            //  funcs will do it internally...
            //  (or maybe we can collapse if cd exists? edge-collapse doesn't check for it explicitly...)
            ProcessResult retVal = ProcessResult.Failed_OpNotSuccessful;

            int iKeep = b, iCollapse = a;

            // if either vtx is fixed, collapse to that position
            if (collapse_to == b)
            {
                vNewPos = vB;
            }
            else if (collapse_to == a)
            {
                iKeep   = a; iCollapse = b;
                vNewPos = vA;
            }
            else
            {
                vNewPos = get_projected_collapse_position(iKeep, vNewPos);
            }

            // check if this collapse will create a normal flip. Also checks
            // for invalid collapse nbrhood, since we are doing one-ring iter anyway.
            // [TODO] could we skip this one-ring check in CollapseEdge? pass in hints?
            if (creates_flip_or_invalid(a, b, ref vNewPos, t0, t1) || creates_flip_or_invalid(b, a, ref vNewPos, t0, t1))
            {
                retVal = ProcessResult.Ignored_CreatesFlip;
                goto skip_to_end;
            }

            // lots of cases where we cannot collapse, but we should just let
            // mesh sort that out, right?
            COUNT_COLLAPSES++;
            DMesh3.EdgeCollapseInfo collapseInfo;
            MeshResult result = mesh.CollapseEdge(iKeep, iCollapse, out collapseInfo);

            if (result == MeshResult.Ok)
            {
                collapseToV = iKeep;
                mesh.SetVertex(iKeep, vNewPos);
                if (constraints != null)
                {
                    constraints.ClearEdgeConstraint(edgeID);
                    constraints.ClearEdgeConstraint(collapseInfo.eRemoved0);
                    if (collapseInfo.eRemoved1 != DMesh3.InvalidID)
                    {
                        constraints.ClearEdgeConstraint(collapseInfo.eRemoved1);
                    }
                    constraints.ClearVertexConstraint(iCollapse);
                }
                OnEdgeCollapse(edgeID, iKeep, iCollapse, collapseInfo);
                DoDebugChecks();

                retVal = ProcessResult.Ok_Collapsed;
            }

skip_to_end:
            end_collapse();
            return(retVal);
        }