Exemple #1
0
            public double Value(ref Vector3d pt)
            {
                double winding = Spatial.FastWindingNumber(pt);

                // shift zero-isocontour to winding isovalue, and then flip sign
                return(-(winding - IsoValue));
            }
            public bool Contains(ComponentMesh mesh2, double fIso = 0.5f)
            {
                if (this.Spatial == null)
                {
                    return(false);
                }
                // make sure FWN is available
                this.Spatial.FastWindingNumber(Vector3d.Zero);

                // block-parallel iteration provides a reasonable speedup
                int  NV        = mesh2.Mesh.VertexCount;
                bool contained = true;

                gParallel.BlockStartEnd(0, NV - 1, (a, b) => {
                    if (contained == false)
                    {
                        return;
                    }
                    for (int vi = a; vi <= b && contained; vi++)
                    {
                        Vector3d v = mesh2.Mesh.GetVertex(vi);
                        if (Math.Abs(Spatial.FastWindingNumber(v)) < fIso)
                        {
                            contained = false;
                            break;
                        }
                    }
                }, 100);

                return(contained);
            }
Exemple #3
0
        /// <summary>
        /// Directly evaluate the winding number inside the marching cubes,
        /// instead of sampling onto a grid. More precise, basically.
        /// </summary>
        protected virtual void update_winding_exact()
        {
            DMesh3 meshIn = MeshSource.GetDMeshUnsafe();

            if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp)
            {
                spatialPro = new DMeshAABBTreePro(meshIn, true);
                spatialPro.FastWindingNumber(Vector3d.Zero);
                spatial_timestamp = meshIn.ShapeTimestamp;
            }
            if (is_invalidated())
            {
                return;
            }

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = new WindingNumberImplicit(spatialPro, winding_iso);
            c.IsoValue = 0.0;
            c.Bounds   = meshIn.CachedBounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubesPro.RootfindingModes.Bisection;
            c.RootModeSteps = 5;

            c.CancelF = is_invalidated;
            c.GenerateContinuation(meshIn.Vertices());
            if (is_invalidated())
            {
                return;
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return;
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return;
            }

            if (is_invalidated())
            {
                return;
            }

            ResultMesh = c.Mesh;
        }
        public virtual void Update()
        {
            base.begin_update();
            int start_timestamp = this.CurrentInputTimestamp;

            if (MeshSource == null)
            {
                throw new Exception("RemoveHiddenFacesOp: must set valid MeshSource to compute!");
            }

            try {
                DMesh3 meshIn = MeshSource.GetDMeshUnsafe();
                if (cachedSpatial == null || spatial_cache_timstamp != meshIn.ShapeTimestamp)
                {
                    cachedSpatial = new DMeshAABBTreePro(meshIn, true);
                    cachedSpatial.FastWindingNumber(Vector3d.Zero);
                    spatial_cache_timstamp = meshIn.ShapeTimestamp;
                }
                DMesh3 editMesh = new DMesh3(meshIn);

                RemoveOccludedTriangles remove = new RemoveOccludedTriangles(editMesh, cachedSpatial)
                {
                    InsideMode = (RemoveOccludedTriangles.CalculationMode)(int) inside_mode,
                    PerVertex  = all_hidden_vertices
                };
                remove.Progress = new ProgressCancel(is_invalidated);

                if (remove.Apply() == false)
                {
                    ResultMesh     = null;
                    RemovedTris    = null;
                    RemovedSubmesh = null;
                }
                else
                {
                    ResultMesh     = editMesh;
                    RemovedTris    = remove.RemovedT;
                    RemovedSubmesh = new DSubmesh3(MeshSource.GetDMeshUnsafe(), RemovedTris);
                }

                base.complete_update();
            } catch (Exception e) {
                PostOnOperatorException(e);
                ResultMesh = base.make_failure_output(MeshSource.GetDMeshUnsafe());
                base.complete_update();
            }
        }
Exemple #5
0
 public double Value(ref Vector3d pt)
 {
     return(Spatial.FastWindingNumber(pt));
 }
Exemple #6
0
        /// <summary>
        /// this variant use a lazy-evaluation version of the grid, and continuation-MC,
        /// so the marching cubes pulls values from the grid that are evaluated on-the-fly.
        /// In theory this should be comparable or faster than the narrow-band version,
        /// practice it is 10-20% slower...?? possible reasons:
        ///    - spinlock contention
        ///    - lots of duplicate grid evaluations because CachingDenseGridTrilinearImplicit does not use locking
        ///
        /// However, because it can re-use grid values, changing the isovalue is
        /// *much* faster and so it makes sense if the mesh is not closed...
        /// </summary>
        protected virtual void update_winding_fast()
        {
            DMesh3 meshIn = MeshSource.GetDMeshUnsafe();

            if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp)
            {
                spatialPro = new DMeshAABBTreePro(meshIn, true);
                spatialPro.FastWindingNumber(Vector3d.Zero);
                spatial_timestamp = meshIn.ShapeTimestamp;
            }
            if (is_invalidated())
            {
                return;
            }

            if (cached_lazy_mwn_grid == null ||
                grid_cell_size != cached_lazy_mwn_grid.CellSize)
            {
                // figure out origin & dimensions
                AxisAlignedBox3d bounds       = meshIn.CachedBounds;
                float            fBufferWidth = 2 * (float)grid_cell_size;
                Vector3d         origin       = (Vector3f)bounds.Min - fBufferWidth * Vector3f.One;
                Vector3f         max          = (Vector3f)bounds.Max + fBufferWidth * Vector3f.One;
                int ni = (int)((max.x - origin.x) / (float)grid_cell_size) + 1;
                int nj = (int)((max.y - origin.y) / (float)grid_cell_size) + 1;
                int nk = (int)((max.z - origin.z) / (float)grid_cell_size) + 1;

                var grid = new CachingDenseGridTrilinearImplicit(origin, grid_cell_size, new Vector3i(ni, nj, nk));
                grid.AnalyticF = new WindingField(spatialPro);

                cached_lazy_mwn_grid = grid;
                cached_mwn_bounds    = meshIn.CachedBounds;
            }

            WindingFieldImplicit iso = new WindingFieldImplicit(cached_lazy_mwn_grid, winding_iso);

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = iso;
            c.Bounds   = cached_mwn_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubesPro.RootfindingModes.Bisection;
            c.RootModeSteps = 10;

            c.CancelF = is_invalidated;
            c.GenerateContinuation(meshIn.Vertices());
            if (is_invalidated())
            {
                return;
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return;
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return;
            }

            // reproject - if we want to do this, we need to create spatial and meshIn above!
            gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => {
                if (is_invalidated())
                {
                    return;
                }
                Vector3d v = c.Mesh.GetVertex(vid);
                int tid    = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo);
                if (tid != DMesh3.InvalidID)
                {
                    var query = MeshQueries.TriangleDistance(meshIn, tid, v);
                    if (v.Distance(query.TriangleClosest) < grid_cell_size)
                    {
                        c.Mesh.SetVertex(vid, query.TriangleClosest);
                    }
                }
            });

            if (is_invalidated())
            {
                return;
            }

            ResultMesh = c.Mesh;
        }
Exemple #7
0
        /// <summary>
        /// Sample analytic winding number into grid in narrow-band around target isovalue,
        /// and then extract using marching cubes.
        ///
        /// TODO: don't need to discard current grid when isovalue changes, just need to
        ///   re-run the front propagation part of mwn.Compute()!
        ///   If this is done, then use this instead of update_winding_fast() for open meshes
        /// </summary>
        protected virtual void update_winding()
        {
            DMesh3 meshIn = MeshSource.GetDMeshUnsafe();

            if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp)
            {
                spatialPro = new DMeshAABBTreePro(meshIn, true);
                spatialPro.FastWindingNumber(Vector3d.Zero);
                spatial_timestamp = meshIn.ShapeTimestamp;
            }
            if (is_invalidated())
            {
                return;
            }

            if (cached_mwn_grid == null ||
                grid_cell_size != cached_mwn_grid.CellSize ||
                (float)winding_iso != cached_mwn_grid.IsoValue)
            {
                Func <Vector3d, double> fastWN = (q) => { return(spatialPro.FastWindingNumber(q)); };
                var mwn = new MeshScalarSamplingGrid(meshIn, grid_cell_size, fastWN)
                {
                    IsoValue = (float)winding_iso
                };
                mwn.CancelF = is_invalidated;
                mwn.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_mwn_grid   = mwn;
                cached_mwn_bounds = meshIn.CachedBounds;
            }

            MarchingCubes c = new MarchingCubes();

            c.Implicit = new SampledGridImplicit(cached_mwn_grid);
            c.IsoValue = 0.0;
            c.Bounds   = cached_mwn_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.Bisection;
            c.RootModeSteps = 10;

            c.CancelF = is_invalidated;
            c.Generate();
            if (is_invalidated())
            {
                return;
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return;
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return;
            }

            // reproject - if we want to do this, we need to create spatial and meshIn above!
            gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => {
                if (is_invalidated())
                {
                    return;
                }
                Vector3d v = c.Mesh.GetVertex(vid);
                int tid    = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo);
                if (tid != DMesh3.InvalidID)
                {
                    var query = MeshQueries.TriangleDistance(meshIn, tid, v);
                    if (v.Distance(query.TriangleClosest) < grid_cell_size)
                    {
                        c.Mesh.SetVertex(vid, query.TriangleClosest);
                    }
                }
            });

            if (is_invalidated())
            {
                return;
            }

            ResultMesh = c.Mesh;
        }
Exemple #8
0
        public virtual bool Apply()
        {
            DMesh3 testAgainstMesh = Mesh;

            if (InsideMode == CalculationMode.RayParity)
            {
                MeshBoundaryLoops loops = new MeshBoundaryLoops(testAgainstMesh);
                if (loops.Count > 0)
                {
                    testAgainstMesh = new DMesh3(Mesh);
                    foreach (var loop in loops)
                    {
                        if (Cancelled())
                        {
                            return(false);
                        }
                        SimpleHoleFiller filler = new SimpleHoleFiller(testAgainstMesh, loop);
                        filler.Fill();
                    }
                }
            }

            DMeshAABBTreePro spatial = (Spatial != null && testAgainstMesh == Mesh) ?
                                       Spatial : new DMeshAABBTreePro(testAgainstMesh, true);

            if (InsideMode == CalculationMode.AnalyticWindingNumber)
            {
                spatial.WindingNumber(Vector3d.Zero);
            }
            else if (InsideMode == CalculationMode.FastWindingNumber)
            {
                spatial.FastWindingNumber(Vector3d.Zero);
            }

            if (Cancelled())
            {
                return(false);
            }

            // ray directions
            List <Vector3d> ray_dirs = null; int NR = 0;

            if (InsideMode == CalculationMode.SimpleOcclusionTest)
            {
                ray_dirs = new List <Vector3d>();
                ray_dirs.Add(Vector3d.AxisX); ray_dirs.Add(-Vector3d.AxisX);
                ray_dirs.Add(Vector3d.AxisY); ray_dirs.Add(-Vector3d.AxisY);
                ray_dirs.Add(Vector3d.AxisZ); ray_dirs.Add(-Vector3d.AxisZ);
                NR = ray_dirs.Count;
            }

            Func <Vector3d, bool> isOccludedF = (pt) => {
                if (InsideMode == CalculationMode.RayParity)
                {
                    return(spatial.IsInside(pt));
                }
                else if (InsideMode == CalculationMode.AnalyticWindingNumber)
                {
                    return(spatial.WindingNumber(pt) > WindingIsoValue);
                }
                else if (InsideMode == CalculationMode.FastWindingNumber)
                {
                    return(spatial.FastWindingNumber(pt) > WindingIsoValue);
                }
                else
                {
                    for (int k = 0; k < NR; ++k)
                    {
                        int hit_tid = spatial.FindNearestHitTriangle(new Ray3d(pt, ray_dirs[k]));
                        if (hit_tid == DMesh3.InvalidID)
                        {
                            return(false);
                        }
                    }
                    return(true);
                }
            };

            bool cancel = false;

            BitArray vertices = null;

            if (PerVertex)
            {
                vertices = new BitArray(Mesh.MaxVertexID);

                MeshNormals normals = null;
                if (Mesh.HasVertexNormals == false)
                {
                    normals = new MeshNormals(Mesh);
                    normals.Compute();
                }

                gParallel.ForEach(Mesh.VertexIndices(), (vid) => {
                    if (cancel)
                    {
                        return;
                    }
                    if (vid % 10 == 0)
                    {
                        cancel = Cancelled();
                    }

                    Vector3d c    = Mesh.GetVertex(vid);
                    Vector3d n    = (normals == null) ? Mesh.GetVertexNormal(vid) : normals[vid];
                    c            += n * NormalOffset;
                    vertices[vid] = isOccludedF(c);
                });
            }
            if (Cancelled())
            {
                return(false);
            }

            RemovedT = new List <int>();
            SpinLock removeLock = new SpinLock();

            gParallel.ForEach(Mesh.TriangleIndices(), (tid) => {
                if (cancel)
                {
                    return;
                }
                if (tid % 10 == 0)
                {
                    cancel = Cancelled();
                }

                bool inside = false;
                if (PerVertex)
                {
                    Index3i tri = Mesh.GetTriangle(tid);
                    inside      = vertices[tri.a] || vertices[tri.b] || vertices[tri.c];
                }
                else
                {
                    Vector3d c = Mesh.GetTriCentroid(tid);
                    Vector3d n = Mesh.GetTriNormal(tid);
                    c         += n * NormalOffset;
                    inside     = isOccludedF(c);
                }

                if (inside)
                {
                    bool taken = false;
                    removeLock.Enter(ref taken);
                    RemovedT.Add(tid);
                    removeLock.Exit();
                }
            });

            if (Cancelled())
            {
                return(false);
            }

            if (RemovedT.Count > 0)
            {
                MeshEditor editor = new MeshEditor(Mesh);
                bool       bOK    = editor.RemoveTriangles(RemovedT, true);
                RemoveFailed = (bOK == false);
            }

            return(true);
        }