Beispiel #1
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            int        num_cells = 128;
            DMesh3_goo dMsh_goo  = null;

            DA.GetData(0, ref dMsh_goo);
            DA.GetData(1, ref num_cells);

            DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value);
            double cell_size = dMsh_copy.CachedBounds.MaxDim / num_cells;

            DMeshAABBTree3 spatial = new DMeshAABBTree3(dMsh_copy, autoBuild: true);

            AxisAlignedBox3d  bounds   = dMsh_copy.CachedBounds;
            double            cellsize = bounds.MaxDim / num_cells;
            ShiftGridIndexer3 indexer  = new ShiftGridIndexer3(bounds.Min, cellsize);

            Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells));

            foreach (Vector3i idx in bmp.Indices())
            {
                g3.Vector3d v = indexer.FromGrid(idx);
                bmp.Set(idx, spatial.IsInside(v));
            }

            VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator();

            voxGen.Voxels = bmp;
            voxGen.Generate();
            DMesh3 voxMesh = voxGen.Meshes[0];

            var vecSize = dMsh_copy.CachedBounds.Extents;
            var box     = dMsh_copy.GetBounds();

            // Scale voxel mesh
            //MeshTransforms.Scale(voxMesh,)

            DA.SetData(0, voxMesh);
        }
Beispiel #2
0
        public static bool isCoulumnInObj(Bitmap3 bmp, int zi, int zj, int x, int z)
        {
            bool visitedInObject = false;

            for (int y = zi; y < zj; y++)
            {
                if (y < 0)
                {
                    continue;
                }
                if (y >= bmp.Dimensions.y)
                {
                    if (visitedInObject)
                    {
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                if (!bmp.Get(createVector(x, y, z)))
                {
                    return(false);
                }
                else
                {
                    visitedInObject = true;
                }
            }
            if (visitedInObject)
            {
                return(true);
            }
            return(false);
        }
Beispiel #3
0
        public static DMesh3 MineCraft(DMesh3 mesh, int num_cells, out double scalefactor)
        {
            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, autoBuild: true);


            AxisAlignedBox3d bounds   = mesh.CachedBounds;
            double           cellsize = bounds.MaxDim / num_cells;

            scalefactor = cellsize;

            ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min, cellsize);

            Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells));

            foreach (Vector3i idx in bmp.Indices())
            {
                g3.Vector3d v = indexer.FromGrid(idx);
                if (spatial.IsInside(v))
                {
                    bmp.Set(idx, true);
                }
                else
                {
                    bmp.Set(idx, false);
                }
            }

            VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator();

            voxGen.Voxels = bmp;
            voxGen.Generate();

            DMesh3 voxMesh = voxGen.Meshes[0];

            return(voxMesh);
        }
Beispiel #4
0
        static void Main(string[] args)
        {
            Console.WriteLine("Path: ");
            string pathToFile = Console.ReadLine();

            Console.WriteLine("Weight Mode?(Y/N): ");
            string     answer = Console.ReadLine();
            List <int> input  = new List <int>();
            Dictionary <int, double> weights = new Dictionary <int, double>();

            if (answer.ToUpper() == "Y")
            {
                int size  = -1;
                int enter = 1;
                while (enter > 0)
                {
                    Console.WriteLine("Please enter slice size: ");
                    size = Convert.ToInt32(Console.ReadLine());
                    if (size <= 0)
                    {
                        enter = -1;
                    }
                    if (enter > 0)
                    {
                        Console.WriteLine("weight : ");
                        if (!weights.ContainsKey(size) && enter > 0)
                        {
                            double wg = -1;
                            wg = Convert.ToDouble(Console.ReadLine());
                            if (wg > 0.0)
                            {
                                weights.Add(size, wg);
                                input.Add(size);
                            }
                            else
                            {
                                Console.WriteLine("set default weight 1");
                                weights.Add(size, 1);
                                input.Add(size);
                            }
                        }
                    }
                }
                weightsOn = true;
            }
            else
            {
                Console.WriteLine("Insert heights: ");
                string s = Console.ReadLine();
                input     = s.Split(' ').Select(t => Convert.ToInt32(t)).ToList <int>();
                weightsOn = false;
            }


            HashSet <int> legitSliceHights = new HashSet <int>(input);
            //"C:\\Users\\VladKo\\Downloads\\bunny.obj"
            Bitmap3 bmp = createVoxelizedRepresentation(pathToFile);

            printVoxelizedRepresentation(bmp, "C:\\Users\\VladKo\\Downloads\\inputVox.obj");
            if (test)
            {
                getIntersections(60, 50, bmp).ForEach(Console.WriteLine);
            }
            Tuple <Dictionary <Tuple <int, int>, int>, Dictionary <Tuple <int, int, int, int>, int> > errorAndSum = calcErrorAndSum(bmp, legitSliceHights.Max(), legitSliceHights.Min());
            Dictionary <Tuple <int, int>, Tuple <int, int> > algResults = optDiscreteSlicingAlgo(errorAndSum.Item1, legitSliceHights, bmp.Dimensions.y);
            Tuple <int, int> startPoint = findStartPoint(algResults, bmp.Dimensions.y, legitSliceHights.Max(), legitSliceHights.Min());
            List <int>       path       = getOptSlice(startPoint, algResults, legitSliceHights.Min(), bmp.Dimensions.y, weights); //from top to bottom
            Vector3i         newObjDim  = createVector(bmp.Dimensions.x, path.First() - path.Last(), bmp.Dimensions.z);
            Bitmap3          outputObj  = createNewObjectForPriniting(path, errorAndSum.Item2, newObjDim, bmp);

            printVoxelizedRepresentation(outputObj, "C:\\Users\\VladKo\\Downloads\\outputVox.obj");
        }
Beispiel #5
0
        public static Bitmap3 createNewObjectForPriniting(List <int> path, Dictionary <Tuple <int, int, int, int>, int> sumDic, Vector3i newObjDim, Bitmap3 oldObj)
        {
            Bitmap3 voxPrintResult = new Bitmap3(newObjDim);

            foreach (Vector3i idx in voxPrintResult.Indices()) //initialize object
            {
                voxPrintResult.Set(idx, false);
            }
            for (int i = 0; i < path.Count - 1; i++)
            { //-1 because we want to take every time the range Zj to Zi where Zj > Zi
                int zj = path[i] - path.Last();
                int zi = path[i + 1] - path.Last();
                for (int x = 0; x < voxPrintResult.Dimensions.x; x++)
                {
                    for (int z = 0; z < voxPrintResult.Dimensions.z; z++)
                    {
                        Tuple <int, int, int, int> key = new Tuple <int, int, int, int>(zi, zj, x, z);
                        if ((sumDic.ContainsKey(key) && sumDic[key] >= 0) || isCoulumnInObj(oldObj, zi, zj, x, z))
                        {
                            for (int y = zi; y < zj; y++)
                            {
                                voxPrintResult.Set(createVector(x, y, z), true);
                            }
                        }
                    }
                }
            }
            return(voxPrintResult);
        }
Beispiel #6
0
        public static Tuple <Dictionary <Tuple <int, int>, int>, Dictionary <Tuple <int, int, int, int>, int> > calcErrorAndSum(Bitmap3 bmp, int tmax, int tmin)
        {
            Dictionary <Tuple <int, int>, int>           errorDic = new Dictionary <Tuple <int, int>, int>();           //key: zi,zj value: total error
            Dictionary <Tuple <int, int, int, int>, int> sumDic   = new Dictionary <Tuple <int, int, int, int>, int>(); //key: zi,zj,x,z value: sum
            List <int> intersectionList;

            //zerro all errors
            for (int zi = 1 - tmax; zi <= bmp.Dimensions.y + tmax; zi++)
            {
                for (int zj = zi; zj <= Math.Min(zi + tmax, bmp.Dimensions.y + tmax); zj++)
                {
                    Tuple <int, int> key = new Tuple <int, int>(zi, zj);
                    errorDic[key] = 0;
                }
            }

            //run for each x and z (2D looking from top of object)
            for (int x = 0; x < bmp.Dimensions.x; x++)
            {
                for (int z = 0; z < bmp.Dimensions.z; z++)
                {
                    //calculate error and sum for specific x and y
                    intersectionList = getIntersections(x, z, bmp);
                    for (int k = 0; k < intersectionList.Count; k++)
                    {
                        //check for null pointer exception
                        int zi;
                        if (k > 0)
                        {
                            zi = Math.Max(intersectionList[k] - tmax, intersectionList[k - 1]);
                        }
                        else
                        {
                            zi = intersectionList[k] - tmax;
                        }
                        for (; zi <= intersectionList[k]; zi++)
                        { //check ranges!
                            for (int zj = intersectionList[k]; zj <= zi + tmax; zj++)
                            {
                                int s = (int)Math.Pow(-1, k) * (zi - intersectionList[k]);
                                int l = k + 1;
                                while (l < intersectionList.Count && intersectionList[l] < zj)
                                {
                                    s += (int)Math.Pow(-1, l) * (intersectionList[l - 1] - intersectionList[l]);
                                    l++;
                                }
                                s += (int)Math.Pow(-1, l) * (intersectionList[l - 1] - zj);
                                Tuple <int, int, int, int> sumKey = new Tuple <int, int, int, int>(zi, zj, x, z);
                                Tuple <int, int>           key    = new Tuple <int, int>(zi, zj);
                                if (!sumDic.ContainsKey(sumKey)) //CHECK THIS OUT IT LOOKS BAD!!! (IN THE LOOK WE REPEAT CALCULATION FOR ZI,ZJ,X,Z!!!!
                                {
                                    sumDic.Add(sumKey, s);
                                    int error = zj - zi - s;
                                    if (errorDic.ContainsKey(key)) //check if need to add prev error
                                    {
                                        errorDic[key] = errorDic[key] + error;
                                    }
                                    else
                                    {
                                        errorDic[key] = error;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(new Tuple <Dictionary <Tuple <int, int>, int>, Dictionary <Tuple <int, int, int, int>, int> >(errorDic, sumDic));
        }
        void make_grid(Vector3f origin, float dx,
                       int ni, int nj, int nk,
                       DenseGrid3f scalars)
        {
            scalars.resize(ni, nj, nk);
            scalars.assign(float.MaxValue);             // sentinel

            if (DebugPrint)
            {
                System.Console.WriteLine("start");
            }

            // Ok, because the whole idea is that the surface might have holes, we are going to
            // compute values along known triangles and then propagate the computed region outwards
            // until any iso-sign-change is surrounded.
            // To seed propagation, we compute unsigned SDF and then compute values for any voxels
            // containing surface (ie w/ distance smaller than cellsize)

            // compute unsigned SDF
            var sdf = new MeshSignedDistanceGrid(Mesh, CellSize)
            {
                ComputeSigns = false
            };

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

            DenseGrid3f distances = sdf.Grid;

            if (WantMeshSDFGrid)
            {
                mesh_sdf = sdf;
            }

            if (DebugPrint)
            {
                System.Console.WriteLine("done initial sdf");
            }

            // compute values at surface voxels
            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];

            gParallel.ForEach(gIndices.Grid3IndicesYZ(nj, nk), (jk) =>
            {
                if (CancelF())
                {
                    return;
                }

                for (int i = 0; i < ni; ++i)
                {
                    var ijk    = new Vector3i(i, jk.y, jk.z);
                    float dist = distances[ijk];
                    // this could be tighter? but I don't think it matters...
                    if (dist < CellSize)
                    {
                        var gx       = new Vector3d((float)ijk.x * dx + origin[0], (float)ijk.y * dx + origin[1], (float)ijk.z * dx + origin[2]);
                        scalars[ijk] = (float)ScalarF(gx);
                    }
                }
            });
            if (CancelF())
            {
                return;
            }

            if (DebugPrint)
            {
                System.Console.WriteLine("done narrow-band");
            }

            // Now propagate outwards from computed voxels.
            // Current procedure is to check 26-neighbours around each 'front' voxel,
            // and if there are any sign changes, that neighbour is added to front.
            // Front is initialized w/ all voxels we computed above

            AxisAlignedBox3i bounds = scalars.Bounds;

            bounds.Max -= Vector3i.One;

            // since we will be computing new values as necessary, we cannot use
            // grid to track whether a voxel is 'new' or not.
            // So, using 3D bitmap intead - is updated at end of each pass.
            var bits                = new Bitmap3(new Vector3i(ni, nj, nk));
            var cur_front           = new List <Vector3i>();

            foreach (Vector3i ijk in scalars.Indices())
            {
                if (scalars[ijk] != float.MaxValue)
                {
                    cur_front.Add(ijk);
                    bits[ijk] = true;
                }
            }
            if (CancelF())
            {
                return;
            }

            // Unique set of 'new' voxels to compute in next iteration.
            var queue      = new HashSet <Vector3i>();
            var queue_lock = new SpinLock();

            while (true)
            {
                if (CancelF())
                {
                    return;
                }

                // can process front voxels in parallel
                bool abort = false; int iter_count = 0;
                gParallel.ForEach(cur_front, (ijk) =>
                {
                    Interlocked.Increment(ref iter_count);
                    if (iter_count % 100 == 0)
                    {
                        abort = CancelF();
                    }

                    if (abort)
                    {
                        return;
                    }

                    float val = scalars[ijk];

                    // check 26-neighbours to see if we have a crossing in any direction
                    for (int k = 0; k < 26; ++k)
                    {
                        Vector3i nijk = ijk + gIndices.GridOffsets26[k];
                        if (bounds.Contains(nijk) == false)
                        {
                            continue;
                        }

                        float val2 = scalars[nijk];
                        if (val2 == float.MaxValue)
                        {
                            var gx        = new Vector3d((float)nijk.x * dx + origin[0], (float)nijk.y * dx + origin[1], (float)nijk.z * dx + origin[2]);
                            val2          = (float)ScalarF(gx);
                            scalars[nijk] = val2;
                        }
                        if (bits[nijk] == false)
                        {
                            // this is a 'new' voxel this round.
                            // If we have an iso-crossing, add it to the front next round
                            bool crossing = (val <IsoValue && val2> IsoValue) ||
                                            (val > IsoValue && val2 < IsoValue);
                            if (crossing)
                            {
                                bool taken = false;
                                queue_lock.Enter(ref taken);
                                queue.Add(nijk);
                                queue_lock.Exit();
                            }
                        }
                    }
                });
                if (DebugPrint)
                {
                    System.Console.WriteLine("front has {0} voxels", queue.Count);
                }

                if (queue.Count == 0)
                {
                    break;
                }

                // update known-voxels list and create front for next iteration
                foreach (Vector3i idx in queue)
                {
                    bits[idx] = true;
                }

                cur_front.Clear();
                cur_front.AddRange(queue);
                queue.Clear();
            }
            if (DebugPrint)
            {
                System.Console.WriteLine("done front-prop");
            }

            if (DebugPrint)
            {
                int filled = 0;
                foreach (Vector3i ijk in scalars.Indices())
                {
                    if (scalars[ijk] != float.MaxValue)
                    {
                        filled++;
                    }
                }
                System.Console.WriteLine("filled: {0} / {1}  -  {2}%", filled, ni * nj * nk,
                                         (double)filled / (double)(ni * nj * nk) * 100.0);
            }

            if (CancelF())
            {
                return;
            }

            // fill in the rest of the grid by propagating know values
            fill_spans(ni, nj, nk, scalars);

            if (DebugPrint)
            {
                System.Console.WriteLine("done sweep");
            }
        }
Beispiel #8
0
        public override Schematic WriteSchematic()
        {
            DMesh3           mesh   = StandardMeshReader.ReadMesh(_path);
            AxisAlignedBox3d bounds = mesh.CachedBounds;

            DMeshAABBTree3    spatial  = new DMeshAABBTree3(mesh, autoBuild: true);
            double            cellsize = mesh.CachedBounds.MaxDim / _gridSize;
            ShiftGridIndexer3 indexer  = new ShiftGridIndexer3(bounds.Min, cellsize);

            MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(mesh, cellsize);

            sdf.Compute();

            Bitmap3 bmp = new Bitmap3(sdf.Dimensions);

            Schematic schematic = new Schematic()
            {
                Blocks = new HashSet <Block>(),
                Width  = (ushort)bmp.Dimensions.x,
                Height = (ushort)bmp.Dimensions.y,
                Length = (ushort)bmp.Dimensions.z
            };

            LoadedSchematic.WidthSchematic  = schematic.Width;
            LoadedSchematic.HeightSchematic = schematic.Height;
            LoadedSchematic.LengthSchematic = schematic.Length;

            if (_winding_number != 0)
            {
                spatial.WindingNumber(Vector3d.Zero);  // seed cache outside of parallel eval

                using (ProgressBar progressbar = new ProgressBar())
                {
                    List <Vector3i> list  = bmp.Indices().ToList();
                    int             count = 0;
                    gParallel.ForEach(bmp.Indices(), (idx) =>
                    {
                        Vector3d v = indexer.FromGrid(idx);
                        bmp.SafeSet(idx, spatial.WindingNumber(v) > _winding_number);
                        count++;
                        progressbar.Report(count / (float)list.Count);
                    });
                }
                if (!_excavate)
                {
                    foreach (Vector3i idx in bmp.Indices())
                    {
                        if (bmp.Get(idx))
                        {
                            schematic.Blocks.Add(new Block((ushort)idx.x, (ushort)idx.y, (ushort)idx.z, Color.White.ColorToUInt()));
                        }
                    }
                }
            }
            else
            {
                using (ProgressBar progressbar = new ProgressBar())
                {
                    int             count = bmp.Indices().Count();
                    List <Vector3i> list  = bmp.Indices().ToList();
                    for (int i = 0; i < count; i++)
                    {
                        Vector3i idx      = list[i];
                        float    f        = sdf[idx.x, idx.y, idx.z];
                        bool     isInside = f < 0;
                        bmp.Set(idx, (f < 0));

                        if (!_excavate && isInside)
                        {
                            schematic.Blocks.Add(new Block((ushort)idx.x, (ushort)idx.y, (ushort)idx.z, Color.White.ColorToUInt()));
                        }
                        progressbar.Report((i / (float)count));
                    }
                }
            }



            if (_excavate)
            {
                foreach (Vector3i idx in bmp.Indices())
                {
                    if (bmp.Get(idx) && IsBlockConnectedToAir(bmp, idx))
                    {
                        schematic.Blocks.Add(new Block((ushort)idx.x, (ushort)idx.y, (ushort)idx.z, Color.White.ColorToUInt()));
                    }
                }
            }

            return(schematic);
        }
        void process_version2(DenseGrid3f supportGrid, DenseGridTrilinearImplicit distanceField)
        {
            int      ni = supportGrid.ni, nj = supportGrid.nj, nk = supportGrid.nk;
            float    dx     = (float)CellSize;
            Vector3f origin = this.GridOrigin;

            // sweep values down layer by layer
            DenseGrid2f prev = supportGrid.get_slice(nj - 1, 1);
            DenseGrid2f tmp  = new DenseGrid2f(prev);

            Bitmap3 bmp = new Bitmap3(new Vector3i(ni, nj, nk));

            for (int j = nj - 2; j >= 0; j--)
            {
                // skeletonize prev layer
                DenseGrid2i prev_skel = binarize(prev, 0.0f);
                skeletonize(prev_skel, null, 2);
                //dilate_loners(prev_skel, null, 2);

                if (j == 0)
                {
                    dilate(prev_skel, null, true);
                    dilate(prev_skel, null, true);
                }

                for (int k = 1; k < nk - 1; ++k)
                {
                    for (int i = 1; i < ni - 1; ++i)
                    {
                        bmp[new Vector3i(i, j, k)] = (prev_skel[i, k] == 1) ? true : false;
                    }
                }

                smooth(prev, tmp, 0.5f, 5);

                DenseGrid2f cur = supportGrid.get_slice(j, 1);
                cur.set_min(prev);

                for (int k = 1; k < nk - 1; ++k)
                {
                    for (int i = 1; i < ni - 1; ++i)
                    {
                        float skelf = prev_skel[i, k] > 0 ? -1.0f : int.MaxValue;
                        cur[i, k] = Math.Min(cur[i, k], skelf);

                        if (cur[i, k] < 0)
                        {
                            Vector3d cell_center = new Vector3f(i * dx, j * dx, k * dx) + origin;
                            if (distanceField.Value(ref cell_center) < -CellSize)
                            {
                                cur[i, k] = 1;
                            }
                        }
                    }
                }

                for (int k = 1; k < nk - 1; ++k)
                {
                    for (int i = 1; i < ni - 1; ++i)
                    {
                        if (is_loner(prev_skel, i, k))
                        {
                            foreach (Vector2i d in gIndices.GridOffsets8)
                            {
                                float f = 1.0f / (float)Math.Sqrt(d.x * d.x + d.y * d.y);
                                cur[i + d.x, k + d.y] += -0.25f * f;
                            }
                        }
                    }
                }

                for (int k = 1; k < nk - 1; ++k)
                {
                    for (int i = 1; i < ni - 1; ++i)
                    {
                        supportGrid[i, j, k] = cur[i, k];
                    }
                }

                prev.swap(cur);
            }


            VoxelSurfaceGenerator gen = new VoxelSurfaceGenerator()
            {
                Voxels = bmp
            };

            gen.Generate();
            Util.WriteDebugMesh(gen.Meshes[0], "c:\\scratch\\binary.obj");
        }