Пример #1
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;
        }
Пример #2
0
        protected virtual DMesh3 compute_blend()
        {
            cache_input_sdfs();
            if (is_invalidated())
            {
                return(null);
            }

            ImplicitBlend3d blend = new ImplicitBlend3d()
            {
                A       = cached_isos[0],
                B       = cached_isos[1],
                Blend   = blend_power,
                WeightA = 1.0,
                WeightB = 1.0
            };

            MarchingCubes c = new MarchingCubes();

            c.Implicit = blend;
            c.IsoValue = 0;
            c.Bounds   = blend.Bounds();
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.Bisection;
            c.RootModeSteps = 5;

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

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize / 2, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

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

            return(c.Mesh);
        }
Пример #3
0
        protected virtual void update_level_set()
        {
            double unsigned_offset = Math.Abs(offset_distance);

            if (cached_sdf == null ||
                unsigned_offset > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMesh3 meshIn      = MeshSource.GetDMeshUnsafe();
                int    exact_cells = (int)(unsigned_offset / grid_cell_size) + 1;

                // only use spatial DS if we are computing enough cells
                DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(
                    input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z);
                MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
                {
                    ExactBandWidth = exact_cells
                };
                if (use_spatial != null)
                {
                    sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size;
                    sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
                }

                sdf.CancelF = is_invalidated;
                sdf.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_sdf            = sdf;
                cached_sdf_max_offset = unsigned_offset;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var           iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize);
            MarchingCubes c   = new MarchingCubes();

            c.Implicit = iso;
            c.IsoValue = offset_distance;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(offset_distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            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;
            }

            ResultMesh = c.Mesh;
        }
Пример #4
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;
        }
Пример #5
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;
        }
Пример #6
0
        protected virtual DMesh3 compute_blend_analytic()
        {
            bool          profile = true;
            LocalProfiler p       = null;

            if (profile)
            {
                p = new LocalProfiler();
                p.Start("bvtree");
            }

            compute_cache_lazy_sdfs();
            if (is_invalidated())
            {
                return(null);
            }


            if (profile)
            {
                p.Stop("bvtree");
                p.Start("mc");
            }

            List <BoundedImplicitFunction3d> inputs = new List <BoundedImplicitFunction3d>();

            foreach (CachingMeshSDF sdf in cached_lazy_sdfs)
            {
                var skel_field = new DistanceFieldToSkeletalField()
                {
                    DistanceField = new CachingMeshSDFImplicit(sdf), FalloffDistance = blend_falloff
                };
                inputs.Add(skel_field);
            }

            SkeletalRicciNaryBlend3d blend = new SkeletalRicciNaryBlend3d()
            {
                Children   = inputs, BlendPower = this.blend_power,
                FieldShift = -DistanceFieldToSkeletalField.ZeroIsocontour
            };

            AxisAlignedBox3d use_bounds = source_bounds;

            source_bounds.Expand(blend_falloff);

            MarchingCubesPro c = lazy_mc;

            c.Implicit = blend;
            //c.IsoValue = DistanceFieldToSkeletalField.ZeroIsocontour;
            c.Bounds   = use_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubesPro.RootfindingModes.LerpSteps;
            c.RootModeSteps = 3;
            //c.ParallelCompute = false;

            c.CancelF = is_invalidated;
            c.GenerateContinuation(input_mesh_seeds());
            if (is_invalidated())
            {
                return(null);
            }

            if (profile)
            {
                p.Stop("mc");
                p.Start("reduce");
            }

            c.Mesh.ReverseOrientation();

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize / 2, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

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

            if (profile)
            {
                p.Stop("reduce");
#if G3_USING_UNITY
                UnityEngine.Debug.Log("ANALYTIC BLEND TIME: " + p.AllTimes());
#endif
            }

            return(c.Mesh);
        }
Пример #7
0
        protected virtual DMesh3 compute_blend_bounded()
        {
            bool          profile = true;
            LocalProfiler p       = null;

            if (profile)
            {
                p = new LocalProfiler();
                p.Start("sdf");
            }

            cache_input_sdfs_bounded();
            if (is_invalidated())
            {
                return(null);
            }

            if (profile)
            {
                p.Stop("sdf");
                p.Start("mc");
            }

            List <BoundedImplicitFunction3d> inputs = new List <BoundedImplicitFunction3d>();

            foreach (var sdf in cached_bounded_sdfs)
            {
                var dist_field = new DenseGridTrilinearImplicit(sdf);
                var skel_field = new DistanceFieldToSkeletalField()
                {
                    DistanceField = dist_field, FalloffDistance = blend_falloff
                };
                inputs.Add(skel_field);
            }

            SkeletalRicciNaryBlend3d blend = new SkeletalRicciNaryBlend3d()
            {
                Children = inputs, BlendPower = this.blend_power
            };

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = blend;
            c.IsoValue = DistanceFieldToSkeletalField.ZeroIsocontour;
            c.Bounds   = blend.Bounds();
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubesPro.RootfindingModes.LerpSteps;
            c.RootModeSteps = 3;

            c.CancelF = is_invalidated;
            //c.Generate();
            c.GenerateContinuation(input_mesh_seeds());
            if (is_invalidated())
            {
                return(null);
            }

            if (profile)
            {
                p.Stop("mc");
                p.Start("reduce");
            }

            c.Mesh.ReverseOrientation();

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize / 2, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

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

            if (profile)
            {
                p.Stop("reduce");
#if G3_USING_UNITY
                UnityEngine.Debug.Log("BLEND TIME: " + p.AllTimes());
#endif
            }

            return(c.Mesh);
        }
Пример #8
0
        protected virtual void compute_shell_distancefield()
        {
            if (cached_is_closed == false)
            {
                compute_shell_distancefield_unsigned();
                return;
            }

            double     offset_distance = shell_thickness;
            Interval1d shell_range     = new Interval1d(0, offset_distance);

            if (shell_direction == ShellDirections.Symmetric)
            {
                shell_range = new Interval1d(-offset_distance / 2, offset_distance / 2);
            }
            else if (shell_direction == ShellDirections.Inner)
            {
                shell_range     = new Interval1d(-offset_distance, 0);
                offset_distance = -offset_distance;
            }


            if (cached_sdf == null ||
                shell_thickness > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMesh3 meshIn      = MeshSource.GetDMeshUnsafe();
                int    exact_cells = (int)((shell_thickness) / grid_cell_size) + 1;

                // only use spatial DS if we are computing enough cells
                DMeshAABBTree3         use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z);
                MeshSignedDistanceGrid sdf         = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
                {
                    ExactBandWidth = exact_cells
                };
                if (use_spatial != null)
                {
                    sdf.NarrowBandMaxDistance = shell_thickness + grid_cell_size;
                    sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
                }

                sdf.CancelF = is_invalidated;
                sdf.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_sdf            = sdf;
                cached_sdf_max_offset = shell_thickness;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize);
            BoundedImplicitFunction3d shell_field = (shell_direction == ShellDirections.Symmetric) ?
                                                    (BoundedImplicitFunction3d) new ImplicitShell3d()
            {
                A = iso, Inside = shell_range
            } :
            (BoundedImplicitFunction3d) new ImplicitOffset3d()
            {
                A = iso, Offset = offset_distance
            };
            //var shell_field = new ImplicitShell3d() { A = iso, Inside = shell_range };
            //BoundedImplicitFunction3d shell_field = (signed_field) ?
            //    (BoundedImplicitFunction3d)new ImplicitShell3d() { A = iso, Inside = shell_range } :
            //    (BoundedImplicitFunction3d)new ImplicitOffset3d() { A = iso, Offset = offset_distance };
            //ImplicitOffset3d offset = new ImplicitOffset3d() { A = iso, Offset = offset_distance };

            MarchingCubes c = new MarchingCubes();

            c.Implicit = shell_field;
            c.IsoValue = 0;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(offset_distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            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;
            }

            if (shell_surface_only)
            {
                if (shell_direction == ShellDirections.Inner || shell_direction == ShellDirections.Outer)
                {
                    c.Mesh.AttachMetadata("is_partial", new object());
                }
            }

            ResultMesh = c.Mesh;
        }
Пример #9
0
        protected virtual void compute_shell_distancefield_unsigned()
        {
            double offset_distance = shell_thickness * 0.5;

            if (cached_sdf == null ||
                offset_distance > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMesh3 meshIn              = MeshSource.GetDMeshUnsafe();
                int    exact_cells         = (int)((offset_distance) / grid_cell_size) + 1;
                MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size)
                {
                    ExactBandWidth = exact_cells,
                    ComputeSigns   = false
                };
                sdf.CancelF = is_invalidated;
                sdf.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_sdf            = sdf;
                cached_sdf_max_offset = offset_distance;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var           iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize);
            MarchingCubes c   = new MarchingCubes();

            c.Implicit = iso;
            c.IsoValue = offset_distance;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(offset_distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            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;
            }

            ResultMesh = c.Mesh;
        }
Пример #10
0
        protected virtual DMesh3 update_step_2(DMesh3 meshIn)
        {
            double unsigned_offset = Math.Abs(distance);
            int    exact_cells     = (int)(unsigned_offset / grid_cell_size) + 1;

            // only use spatial DS if we are computing enough cells
            bool compute_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(
                input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z) != null;
            DMeshAABBTree3         use_spatial = (compute_spatial) ? new DMeshAABBTree3(meshIn, true) : null;
            MeshSignedDistanceGrid sdf         = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
            {
                ExactBandWidth = exact_cells
            };

            if (use_spatial != null)
            {
                sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size;
                sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
            }

            sdf.CancelF = is_invalidated;
            sdf.Compute();
            if (is_invalidated())
            {
                return(null);
            }

            var           iso = new DenseGridTrilinearImplicit(sdf.Grid, sdf.GridOrigin, sdf.CellSize);
            MarchingCubes c   = new MarchingCubes();

            c.Implicit = iso;

            if (op_type == OperationTypes.Close)
            {
                c.IsoValue = -distance;
            }
            else
            {
                c.IsoValue = distance;
            }

            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

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

            Reducer r = new Reducer(c.Mesh);

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

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

            return(c.Mesh);
        }
Пример #11
0
        protected virtual DMesh3 compute_inset(DMesh3 meshIn)
        {
            double unsigned_offset = Math.Abs(distance);

            DMeshAABBTree3 use_spatial = new DMeshAABBTree3(meshIn, true);

            if (is_invalidated())
            {
                return(null);
            }

            CachingMeshSDF sdf = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial);

            sdf.MaxOffsetDistance = (float)unsigned_offset;
            sdf.CancelF           = is_invalidated;
            sdf.Initialize();
            if (is_invalidated())
            {
                return(null);
            }

            var sdf_iso = new CachingMeshSDFImplicit(sdf);
            // currently MCPro-Continuation does not work w/ non-zero
            //   isovalues, so we have to shift our target offset externally
            ImplicitOffset3d iso = new ImplicitOffset3d()
            {
                A = sdf_iso, Offset = -distance
            };

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = iso;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);

            c.CancelF = is_invalidated;
            c.GenerateContinuation(offset_seeds(meshIn, -distance));
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

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

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

            return(c.Mesh);
        }
Пример #12
0
        protected virtual DMesh3 compute_wrap()
        {
            DMesh3 meshIn = MeshSource.GetDMeshUnsafe();

            double unsigned_offset = Math.Abs(distance);

            if (cached_sdf == null ||
                unsigned_offset > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMeshAABBTree3 use_spatial = input_spatial;
                CachingMeshSDF sdf         = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial);
                sdf.MaxOffsetDistance = 2 * (float)unsigned_offset;

                sdf.CancelF = is_invalidated;
                sdf.Initialize();
                if (is_invalidated())
                {
                    return(null);
                }

                cached_sdf            = sdf;
                cached_sdf_max_offset = unsigned_offset;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var grid_iso = new CachingMeshSDFImplicit(cached_sdf);
            // currently MCPro-Continuation does not work w/ non-zero
            //   isovalues, so we have to shift our target offset externally
            var iso = new ImplicitOffset3d()
            {
                A = grid_iso, Offset = distance
            };

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = iso;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);

            c.CancelF = is_invalidated;
            c.GenerateContinuation(offset_seeds(meshIn, distance));
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

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

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

            DMesh3 offsetMesh = c.Mesh;

            MeshConnectedComponents comp = new MeshConnectedComponents(offsetMesh);

            comp.FindConnectedT();
            if (is_invalidated())
            {
                return(null);
            }
            DSubmesh3Set subMeshes = new DSubmesh3Set(offsetMesh, comp);

            if (is_invalidated())
            {
                return(null);
            }

            MeshSpatialSort sort = new MeshSpatialSort();

            foreach (var subMesh in subMeshes)
            {
                sort.AddMesh(subMesh.SubMesh, subMesh);
            }
            sort.Sort();
            if (is_invalidated())
            {
                return(null);
            }

            DMesh3 outerMesh = new DMesh3();

            foreach (var solid in sort.Solids)
            {
                DMesh3 outer = solid.Outer.Mesh;
                //if (is_outward_oriented(outer) == false)
                //    outer.ReverseOrientation();
                MeshEditor.Append(outerMesh, outer);
            }
            if (is_invalidated())
            {
                return(null);
            }

            return(compute_inset(outerMesh));
        }
Пример #13
0
        protected virtual DMesh3 compute_wrap()
        {
            cache_input_sdfs();
            if (is_invalidated())
            {
                return(null);
            }

            BoundedImplicitFunction3d iso = null;

            if (op_type == OpTypes.Union)
            {
                iso = new ImplicitNaryUnion3d()
                {
                    Children = new List <BoundedImplicitFunction3d>(cached_isos)
                };
            }
            else if (op_type == OpTypes.Intersection)
            {
                iso = new ImplicitNaryIntersection3d()
                {
                    Children = new List <BoundedImplicitFunction3d>(cached_isos)
                };
            }
            else if (op_type == OpTypes.Difference)
            {
                iso = new ImplicitNaryDifference3d()
                {
                    A    = cached_isos[0],
                    BSet = new List <BoundedImplicitFunction3d>(cached_isos.Skip(1))
                };
            }

            MarchingCubes c = new MarchingCubes();

            c.Implicit = iso;
            c.IsoValue = 0;
            c.Bounds   = iso.Bounds();
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.Bisection;
            c.RootModeSteps = 5;

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

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize / 2, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

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

            return(c.Mesh);
        }
Пример #14
0
        protected virtual void compute_hollow()
        {
            double offset_distance = -wall_thickness;

            if (cached_sdf == null ||
                wall_thickness > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMesh3 meshIn      = MeshSource.GetDMeshUnsafe();
                int    exact_cells = (int)((wall_thickness) / grid_cell_size) + 1;

                // only use spatial DS if we are computing enough cells
                DMeshAABBTree3         use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z);
                MeshSignedDistanceGrid sdf         = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
                {
                    ExactBandWidth = exact_cells
                };
                if (use_spatial != null)
                {
                    sdf.NarrowBandMaxDistance = wall_thickness + grid_cell_size;
                    sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
                }

                sdf.CancelF = is_invalidated;
                sdf.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_sdf            = sdf;
                cached_sdf_max_offset = wall_thickness;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize);
            ImplicitOffset3d shell_field = new ImplicitOffset3d()
            {
                A = iso, Offset = offset_distance
            };
            ImplicitFunction3d use_iso = shell_field;


            if (enable_infill)
            {
                GridDistanceField grid_df = new GridDistanceField()
                {
                    CellSize = infill_spacing,
                    Radius   = infill_thickness * 0.5,
                    Origin   = cached_sdf.GridOrigin
                };
                ImplicitDifference3d diff = new ImplicitDifference3d()
                {
                    A = shell_field, B = grid_df
                };
                use_iso = diff;
            }


            MarchingCubes c = new MarchingCubes();

            c.Implicit = use_iso;
            c.IsoValue = 0;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(offset_distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            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;
            }

            //r.ReduceToTriangleCount(c.Mesh.TriangleCount / 5);
            //if (is_invalidated())
            //    return;

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

            c.Mesh.AttachMetadata("is_partial", new object());

            ResultMesh = c.Mesh;
        }