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