/* * This function calculates the min and max x/y coordinates of this slice */ public static MinMax_XY CalcMinMax_XY(List <Line2d> lines2d) { Line2d l1 = (Line2d)lines2d[0]; MinMax_XY mm = new MinMax_XY(); //start the min / max off with some valid values //mm.xmin = mm.xmax = l1.p1.x; //mm.ymin = mm.ymax = l1.p1.y; mm.xmin = lines2d.Select(a => a.p1.x).Min(); mm.xmax = lines2d.Select(a => a.p1.x).Max(); mm.ymin = lines2d.Select(a => a.p1.y).Min(); mm.ymax = lines2d.Select(a => a.p1.y).Max(); //foreach (Line2d ln in lines2d) //{ // if (ln.p1.x < mm.xmin) mm.xmin = ln.p1.x; // if (ln.p2.x < mm.xmin) mm.xmin = ln.p2.x; // if (ln.p1.x > mm.xmax) mm.xmax = ln.p1.x; // if (ln.p2.x > mm.xmax) mm.xmax = ln.p2.x; // if (ln.p1.y < mm.ymin) mm.ymin = ln.p1.y; // if (ln.p2.y < mm.ymin) mm.ymin = ln.p2.y; // if (ln.p1.y > mm.ymax) mm.ymax = ln.p1.y; // if (ln.p2.y > mm.ymax) mm.ymax = ln.p2.y; //} return(mm); }
public Bitmap RenderSlice(SliceBuildConfig sp) { // create a new bitmap that will be used to draw into Bitmap bmp = new Bitmap(sp.xres, sp.yres); Graphics graph = Graphics.FromImage(bmp); Point pnt1 = new Point(); // create some points for drawing Point pnt2 = new Point(); Pen pen = new Pen(Color.White, 1); graph.Clear(Color.Black); //convert all to 2d lines ArrayList lines2d = Get2dLines(sp); Render2dlines(graph, lines2d, sp); // find the x/y min/max MinMax_XY mm = CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) { // get a line of lines that intersect this 2d line ArrayList intersecting = GetIntersecting2dYLines(y, lines2d); // get the list of point intersections ArrayList points = GetIntersectingPoints(y, intersecting); // sort the points in increasing x order //SortXIncreasing(points); points.Sort(); // draw the X-Spans (should be even number) // For a given pair of intersectin points // (Xi, Y), (Xj, Y) // −> Fill ceiling(Xi) to floor(Xj) if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { Point2d p1 = (Point2d)points[cnt]; Point2d p2 = (Point2d)points[cnt + 1]; pnt1.X = p1.x + sp.XOffset; pnt1.Y = p1.y + sp.YOffset; pnt2.X = p2.x + sp.XOffset; pnt2.Y = p2.y + sp.YOffset; graph.DrawLine(pen, pnt1, pnt2); } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count); } } return(bmp); }
/* * This function calculates the min and max x/y coordinates of this slice */ public static MinMax_XY CalcMinMax_XY(List <Line2d> lines2d) { Line2d l1 = (Line2d)lines2d[0]; MinMax_XY mm = new MinMax_XY(); //start the min / max off with some valid values mm.xmin = mm.xmax = l1.p1.x; mm.ymin = mm.ymax = l1.p1.y; foreach (Line2d ln in lines2d) { if (ln.p1.x < mm.xmin) { mm.xmin = ln.p1.x; } if (ln.p2.x < mm.xmin) { mm.xmin = ln.p2.x; } if (ln.p1.x > mm.xmax) { mm.xmax = ln.p1.x; } if (ln.p2.x > mm.xmax) { mm.xmax = ln.p2.x; } if (ln.p1.y < mm.ymin) { mm.ymin = ln.p1.y; } if (ln.p2.y < mm.ymin) { mm.ymin = ln.p2.y; } if (ln.p1.y > mm.ymax) { mm.ymax = ln.p1.y; } if (ln.p2.y > mm.ymax) { mm.ymax = ln.p2.y; } } return(mm); }
/// <summary> /// This function will iterate through the optimized loops /// and determine if they are interior or exterior and tag them appropriately /// </summary> public void DetermineInteriorExterior(SliceBuildConfig config) { List <PolyLine3d> allsegments = new List <PolyLine3d>(); foreach (PolyLine3d pln in m_opsegs) { pln.tag = PolyLine3d.TAG_INTERIOR; // mark it as interior List <PolyLine3d> segments = pln.Split(); // split them, retaining the parent allsegments.AddRange(segments); } List <Line2d> lines2d = Get2dLines(config, allsegments); // find the x/y min/max MinMax_XY mm = Slice.CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value { // get a line of lines that intersect this 2d line List <Line2d> intersecting = Slice.GetIntersecting2dYLines(y, lines2d); // get the list of point intersections List <Point2d> points = Slice.GetIntersectingPoints(y, intersecting); // sort the points in increasing x order points.Sort(); if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { // the first point is always an exterior - really? why? Point2d p1 = (Point2d)points[cnt]; if (p1.m_parent != null) { p1.m_parent.tag = PolyLine3d.TAG_EXTERIOR; // mark as exterior } // the second point could be an exterior or interior Point2d p2 = (Point2d)points[cnt + 1]; } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes"); } }// for y = startminY to endY }
/* This function calculates the min and max x/y coordinates of this slice */ public MinMax_XY CalcMinMax_XY(ArrayList lines2d) { Line2d l1 = (Line2d)lines2d[0]; MinMax_XY mm = new MinMax_XY(); //start the min / max off with some valid values mm.xmin = mm.xmax = l1.p1.x; mm.ymin = mm.ymax = l1.p1.y; foreach (Line2d ln in lines2d) { if (ln.p1.x < mm.xmin) mm.xmin = ln.p1.x; if (ln.p2.x < mm.xmin) mm.xmin = ln.p2.x; if (ln.p1.x > mm.xmax) mm.xmax = ln.p1.x; if (ln.p2.x > mm.xmax) mm.xmax = ln.p2.x; if (ln.p1.y < mm.ymin) mm.ymin = ln.p1.y; if (ln.p2.y < mm.ymin) mm.ymin = ln.p2.y; if (ln.p1.y > mm.ymax) mm.ymax = ln.p1.y; if (ln.p2.y > mm.ymax) mm.ymax = ln.p2.y; } return mm; }
//alright, it looks like I'm going to have to code up a 2d scanline fill algorithm // I suppose the first step is to convert all the 3d-ish polyline points in this slice into // 2d polylines, then use those to implement the fill /// <summary> /// This new slicing function renders into a pre-allocated bitmap /// </summary> /// <param name="sp"></param> /// <param name="bmp"></param> public void RenderSlice(SliceBuildConfig sp, ref Bitmap bmp) { try { Graphics graph = Graphics.FromImage(bmp); Point pnt1 = new Point(); // create some points for drawing Point pnt2 = new Point(); Pen pen = new Pen(UVDLPApp.Instance().m_appconfig.m_foregroundcolor, 1); //convert all to 2d lines int hxres = sp.xres / 2; int hyres = sp.yres / 2; List <Line2d> lines2d = Get2dLines(sp, m_segments); if (lines2d.Count == 0) { return; } Render2dlines(graph, lines2d, sp); // find the x/y min/max MinMax_XY mm = CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value { // get a line of lines that intersect this 2d line List <Line2d> intersecting = GetIntersecting2dYLines(y, lines2d); // get the list of point intersections List <Point2d> points = GetIntersectingPoints(y, intersecting); // sort the points in increasing x order //SortXIncreasing(points); points.Sort(); SortBackfaces(points); if (UVDLPApp.Instance().m_slicer.m_slicemethod == Slicer.eSliceMethod.eEvenOdd) { // draw the X-Spans (should be even number) // For a given pair of intersectin points // (Xi, Y), (Xj, Y) // −> Fill ceiling(Xi) to floor(Xj) if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { Point2d p1 = (Point2d)points[cnt]; Point2d p2 = (Point2d)points[cnt + 1]; pnt1.X = (int)(p1.x + sp.XOffset + hxres); pnt1.Y = (int)(p1.y + sp.YOffset + hyres); pnt2.X = (int)(p2.x + sp.XOffset + hxres); pnt2.Y = (int)(p2.y + sp.YOffset + hyres); //graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graph.DrawLine(pen, pnt1.X, pnt1.Y, pnt2.X, pnt2.Y); } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes"); } } else if (UVDLPApp.Instance().m_slicer.m_slicemethod == Slicer.eSliceMethod.eNormalCount) { Point2d p1 = null; Point2d p2 = null; int turncount = 0; if (points.Count != 0) { for (int cnt = 0; cnt < points.Count; cnt++) { if (points[cnt].m_backfacing) { if (turncount == 0) //p1 == null) { p1 = (Point2d)points[cnt]; } turncount++; } else { //if (turncount > 0) turncount--; if ((turncount == 0) && (p1 != null)) { p2 = (Point2d)points[cnt]; pnt1.X = (int)(p1.x + sp.XOffset + hxres); pnt1.Y = (int)(p1.y + sp.YOffset + hyres); pnt2.X = (int)(p2.x + sp.XOffset + hxres); pnt2.Y = (int)(p2.y + sp.YOffset + hyres); //graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graph.DrawLine(pen, pnt1.X, pnt1.Y, pnt2.X, pnt2.Y); p1 = p2; p2 = null; } } } if (turncount != 0)// flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " non equal in/outs = " + turncount + " - Model may have holes"); } } } } } catch (Exception ex) { DebugLogger.Instance().LogError(ex.Message); } }
public Bitmap RenderSlice(SliceBuildConfig sp) { // create a new bitmap that will be used to draw into //Bitmap bmp = new Bitmap(sp.xres, sp.yres); double scaler = 1.5; // specofy the scale factor if (sp.antialiasing == true) { scaler = sp.aaval; } else { scaler = 1.0; // no scaling } double sdpmmx = sp.dpmmX; // save the original dots per mm double sdpmmy = sp.dpmmY; sp.dpmmX *= scaler;// scaler them up. sp.dpmmY *= scaler; //Re-sample to a higher resolution so we can smooth later int ox, oy; ox = sp.xres; // save the original resolution oy = sp.yres; double xs, ys; xs = ((double)sp.xres) * scaler; // scale them up ys = ((double)sp.yres) * scaler; sp.xres = (int)xs; sp.yres = (int)ys; Bitmap bmp = new Bitmap(sp.xres, sp.yres); //Bitmap bmp = new Bitmap((int)xs,(int)ys); Graphics graph = Graphics.FromImage(bmp); Point pnt1 = new Point(); // create some points for drawing Point pnt2 = new Point(); Pen pen = new Pen(Color.White, 1); graph.Clear(Color.Black); //convert all to 2d lines int hxres = sp.xres / 2; int hyres = sp.yres / 2; ArrayList lines2d = Get2dLines(sp); Render2dlines(graph, lines2d, sp); // find the x/y min/max MinMax_XY mm = CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value { // get a line of lines that intersect this 2d line ArrayList intersecting = GetIntersecting2dYLines(y, lines2d); // get the list of point intersections ArrayList points = GetIntersectingPoints(y, intersecting); // sort the points in increasing x order //SortXIncreasing(points); points.Sort(); // draw the X-Spans (should be even number) // For a given pair of intersectin points // (Xi, Y), (Xj, Y) // −> Fill ceiling(Xi) to floor(Xj) if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { Point2d p1 = (Point2d)points[cnt]; Point2d p2 = (Point2d)points[cnt + 1]; pnt1.X = (int)(p1.x + sp.XOffset + hxres); pnt1.Y = (int)(p1.y + sp.YOffset + hyres); pnt2.X = (int)(p2.x + sp.XOffset + hxres); pnt2.Y = (int)(p2.y + sp.YOffset + hyres); //graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graph.DrawLine(pen, pnt1.X, pnt1.Y, pnt2.X, pnt2.Y); } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes"); } } //Rescale the image to re-sample it from a higher res to soften the lines with bicubic interpolation. sp.dpmmX = sdpmmx; sp.dpmmY = sdpmmy; sp.xres = ox; sp.yres = oy; if (sp.antialiasing == true) // we're using anti-aliasing here, so resize the image { return(ReflectY(ResizeImage(bmp, new Size(ox, oy)))); } else { return(ReflectY(bmp)); } //return bmp; }
/// <summary> /// This is the adaptive support generation, it should automatically /// detect overhangs, /// The way that it does this is by generating a closed polyline loop for each layer /// and checking the 2d projection of the current layer with the previous layer /// </summary> public void GenerateAdaptive() { //iterate through all the layers starting from z=0 // check every polyline in the current layer to make sure it is encased or overlaps polylines in the previous layer // generate a list of unsupported polylines // 'check' to see if the polyline can be dropped straight down // this has to do slicing of the scene SliceBuildConfig config = UVDLPApp.Instance().m_buildparms; List <UnsupportedRegions> lstunsup = new List <UnsupportedRegions>(); List <Object3d> lstsupports = new List <Object3d>(); // final list of supports int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config); float zlev = 0.0f; Slice curslice = null; Slice prevslice = null; int hxres = config.xres / 2; int hyres = config.yres / 2; for (int c = 0; c < numslices; c++) { if (m_cancel) { RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCancel, "Support Generation Cancelled", null); return; } RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eProgress, "" + c + "/" + numslices, null); Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev); sl.Optimize();// find loops zlev += (float)config.ZThick; prevslice = curslice; curslice = sl; Bitmap bm = new Bitmap(config.xres, config.yres); if (prevslice != null && curslice != null) { //render current slice curslice.RenderSlice(config, ref bm); //now render the previous slice overtop the current slice in another color Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor; UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.HotPink; //render previous slice over top prevslice.RenderSlice(config, ref bm); UVDLPApp.Instance().m_appconfig.m_foregroundcolor = savecol; // restore the color // create a lock bitmap for faster pixel access LockBitmap lbm = new LockBitmap(bm); lbm.LockBits(); // now, iterate through all optimized polylines in current slice // this approach isn't going to work, we need to iterate through all polyline //segments in a slice at once, each individual segment needs to know 1 thing // 1) the optimized segment it came from foreach (PolyLine3d pln in curslice.m_opsegs) { // each polyline region is checked separately bool plysupported = false; //split this optimized polyline back into 2-point segments for easier use List <PolyLine3d> segments = pln.Split(); List <Line2d> lines2d = Get2dLines(config, segments); // find the x/y min/max MinMax_XY mm = Slice.CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value { // get a line of lines that intersect this 2d line List <Line2d> intersecting = Slice.GetIntersecting2dYLines(y, lines2d); // get the list of point intersections List <Point2d> points = Slice.GetIntersectingPoints(y, intersecting); // sort the points in increasing x order points.Sort(); if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { Point2d p1 = (Point2d)points[cnt]; Point2d p2 = (Point2d)points[cnt + 1]; Point pnt1 = new Point(); // create some points for drawing Point pnt2 = new Point(); pnt1.X = (int)(p1.x + config.XOffset + hxres); pnt1.Y = (int)(p1.y + config.YOffset + hyres); pnt2.X = (int)(p2.x + config.XOffset + hxres); pnt2.Y = (int)(p2.y + config.YOffset + hyres); //iterate from pnt1.X to pnt2.x and check colors for (int xc = pnt1.X; xc < pnt2.X; xc++) { Color checkcol = lbm.GetPixel(xc, pnt1.Y); // need to check the locked BM here for the right color // if the pixel color is the hot pink, then this region has some support // we're going to need to beef this up and probably divide this all into regions on a grid if (checkcol.R == Color.HotPink.R && checkcol.G == Color.HotPink.G && checkcol.B == Color.HotPink.B) { plysupported = true; } } } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes"); } }// for y = startminY to endY if (plysupported == false) { //generate a support, or mark where a support should be... lstunsup.Add(new UnsupportedRegions(pln)); } else { plysupported = true; } } // for each optimized polyline lbm.UnlockBits(); // unlock the bitmap } // prev and current slice are not null } // iterating through all slices RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports); m_generating = false; }
/// <summary> /// NOT CURRENTLY USED /// This is the adaptive support generation, it should automatically /// detect overhangs, /// The way that it does this is by generating a closed polyline loop for each layer /// and checking the 2d projection of the current layer with the previous layer /// </summary> public void GenerateAdaptive() { //iterate through all the layers starting from z=0 // check every polyline in the current layer to make sure it is encased or overlaps polylines in the previous layer // generate a list of unsupported polylines // 'check' to see if the polyline can be dropped straight down // this has to do slicing of the scene try { SliceBuildConfig config = UVDLPApp.Instance().m_buildparms; config.UpdateFrom(UVDLPApp.Instance().m_printerinfo); // make sure we've got the correct display size and PixPerMM values if (UVDLPApp.Instance().m_slicer.SliceFile == null) { SliceFile sf = new SliceFile(config); sf.m_mode = SliceFile.SFMode.eImmediate; UVDLPApp.Instance().m_slicer.SliceFile = sf; // wasn't set } //create new list for each layer to hold unsupported regions List <UnsupportedRegions> lstunsup = new List <UnsupportedRegions>(); List <Object3d> lstsupports = new List <Object3d>(); // final list of supports int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config); float zlev = (float)(config.ZThick / 2.0); Slice curslice = null; Slice prevslice = null; int hxres = config.xres / 2; int hyres = config.yres / 2; for (int c = 0; c < numslices; c++) { //bool layerneedssupport = false; if (m_cancel) { RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCancel, "Support Generation Cancelled", null); return; } RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eProgress, "" + c + "/" + numslices, null); Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev); zlev += (float)config.ZThick; if (sl == null) { continue; } if (sl.m_segments == null) { continue; } if (sl.m_segments.Count == 0) { continue; } sl.Optimize();// find loops //sl.DetermineInteriorExterior(config); // mark the interior/exterior loops prevslice = curslice; curslice = sl; Bitmap bm = new Bitmap(config.xres, config.yres); using (Graphics gfx = Graphics.FromImage(bm)) using (SolidBrush brush = new SolidBrush(Color.Black)) { gfx.FillRectangle(brush, 0, 0, bm.Width, bm.Height); } if (prevslice != null && curslice != null) { //render current slice curslice.RenderSlice(config, ref bm); //now render the previous slice overtop the current slice in another color Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor; UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.HotPink; //render previous slice over top prevslice.RenderSlice(config, ref bm); UVDLPApp.Instance().m_appconfig.m_foregroundcolor = savecol; // restore the color // create a lock bitmap for faster pixel access LockBitmap lbm = new LockBitmap(bm); lbm.LockBits(); // now, iterate through all optimized polylines in current slice // this approach isn't going to work, we need to iterate through all polyline //segments in a slice at once, each individual segment needs to know 1 thing // 1) the optimized segment it came from //iterate through all optimized polygon segments Dictionary <PolyLine3d, bool> supportmap = new Dictionary <PolyLine3d, bool>(); foreach (PolyLine3d pln in curslice.m_opsegs) { bool plysupported = false; List <PolyLine3d> allsegments = new List <PolyLine3d>(); List <PolyLine3d> segments = pln.Split(); // split them, retaining the parent allsegments.AddRange(segments); //add all optimized polyline segments into the supported map supportmap.Add(pln, true); //split this optimized polyline back into 2-point segments for easier use List <Line2d> lines2d = Get2dLines(config, allsegments); if (lines2d.Count == 0) { continue; } // find the x/y min/max MinMax_XY mm = Slice.CalcMinMax_XY(lines2d); // iterate from the ymin to the ymax for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value { // get a line of lines that intersect this 2d line List <Line2d> intersecting = Slice.GetIntersecting2dYLines(y, lines2d); // get the list of point intersections List <Point2d> points = Slice.GetIntersectingPoints(y, intersecting); // sort the points in increasing x order points.Sort(); if (points.Count % 2 == 0) // is even { for (int cnt = 0; cnt < points.Count; cnt += 2) // increment by 2 { Point2d p1 = (Point2d)points[cnt]; Point2d p2 = (Point2d)points[cnt + 1]; Point pnt1 = new Point(); // create some points for drawing Point pnt2 = new Point(); pnt1.X = (int)(p1.x + config.XOffset + hxres); pnt1.Y = (int)(p1.y + config.YOffset + hyres); pnt2.X = (int)(p2.x + config.XOffset + hxres); pnt2.Y = (int)(p2.y + config.YOffset + hyres); //iterate from pnt1.X to pnt2.x and check colors for (int xc = pnt1.X; xc < pnt2.X; xc++) { if (xc >= lbm.Width || xc <= 0) { continue; } if (pnt1.Y >= lbm.Height || pnt1.Y <= 0) { continue; } try { Color checkcol = lbm.GetPixel(xc, pnt1.Y); // need to check the locked BM here for the right color // if the pixel color is the hot pink, then this region has some support // we're going to need to beef this up and probably divide this all into regions on a grid if (checkcol.R == Color.HotPink.R && checkcol.G == Color.HotPink.G && checkcol.B == Color.HotPink.B) { plysupported = true; } } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } } } } else // flag error { DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes"); } }// for y = startminY to endY if (plysupported == false) { // layerneedssupport = true; supportmap[pln] = false; lstunsup.Add(new UnsupportedRegions(pln)); } } // for each optimized polyline lbm.UnlockBits(); // unlock the bitmap } // prev and current slice are not null //if (layerneedssupport) // SaveBM(bm, c); // uncomment this to see the layers that need support } // iterating through all slices // iterate through all unsupported regions // calculate the center // add a support from that region going down to the ground (or closest intersected) int scnt = 0; foreach (UnsupportedRegions region in lstunsup) { Support s = new Support(); Point3d center = region.Center(); // taking the center of the region is a naive approach float lz = center.z; lz += .65f; // why is this offset needed? AddNewSupport(center.x, center.y, center.z, scnt++, null, lstsupports); } RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports); m_generating = false; } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } }