private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf) { if (InvokeRequired) { BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers,sf); })); } else { switch (ev) { case Slicer.eSliceEvent.eSliceStarted: cmdSlice.Text = "Cancel"; prgSlice.Maximum = totallayers - 1; break; case Slicer.eSliceEvent.eLayerSliced: prgSlice.Maximum = totallayers - 1; prgSlice.Value = layer; lblMessage.Text = "Slicing Layer " + (layer + 1).ToString() + " of " + totallayers.ToString(); break; case Slicer.eSliceEvent.eSliceCompleted: lblMessage.Text = "Slicing Completed"; cmdSlice.Text = "Slice!"; Close(); break; case Slicer.eSliceEvent.eSliceCancelled: cmdSlice.Text = "Slice!"; lblMessage.Text = "Slicing Cancelled"; prgSlice.Value = 0; break; } } }
/* GCode Process for building 3d DVP UV objects * <Build Start> * <Slicing Comments> comments containing the slicing and building parameters * <Header Code> start.gcode - commands from this * file are inserted, they contain whatever intiailization sequences are need to initialize the machine * at this point, the build tray is in position to start printing a layer * <Layer Start> * Display the correct image slice for the current layer * Delay for <Layertime> to expose the UV resin * <Layer End> Example: * G1 Z0.05 F10 (move to the layer position .05 mm distance) * (<Layer 0 >) (show the slice image layer) * (<Delay 1000 >) (pause to expose the layer, first layer time is longer) * (<Layer Blank >) (show the blank image layer now) * (pre- lift gcode goes here) * G1 Z5 F10 (Move up (or down) for the lift sequence) * G1 X20 F20 (Move the wiper) * G1 X-20 F20 (Move the wiper back) * G1 Z5 F10 (Move down (or up) for the lift sequence) * (post - lift gcode goes here) * (<Delay blanktime >) (the previous commands will all be run, this command will cause the build manager to delay before moving to the next layer) */ /* This is the main function to generate gcode files for the * already sliced model */ public static GCodeFile Generate(SliceFile sf, MachineConfig pi) { String gcode; StringBuilder sb = new StringBuilder(); double zdist = 0.0; double feedrate = pi.ZMaxFeedrate; // 10mm/min double zdir = 1.0; // assume a bottom up machine int numbottom = sf.m_config.numfirstlayers; if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down) { zdir = -1.0;// top down machine, reverse the z direction } // append the build parameters as reference sb.Append(sf.m_config.ToString()); // append the header sb.Append(sf.m_config.HeaderCode); String firstlayerdelay = "(<Delay> " + sf.m_config.firstlayertime_ms + " )\r\n"; String layerdelay = "(<Delay> " + sf.m_config.layertime_ms + " )\r\n"; String blankdelay = "(<Delay> " + sf.m_config.blanktime_ms + " )\r\n"; String raisetime = "(<Delay> " + sf.m_config.raise_time_ms + " )\r\n"; zdist = sf.m_config.ZThick; for (int c = 0; c < sf.m_slices.Count; c++ ) { //move the z axis to the right layer position // sb.Append("G1 Z" + String.Format("{0:0.00000}", (zdist * zdir)) + " F" + feedrate + "\r\n"); // this is the marker the BuildManager uses to display the correct slice sb.Append( "(<Slice> " + c + " )\r\n"); // add a pause for the UV resin to be set using this image if (c < numbottom)// check for the bottom layers { sb.Append(firstlayerdelay); } else { sb.Append(layerdelay); } sb.Append("(<Slice> Blank )\r\n"); // show the blank layer sb.Append(sf.m_config.PreLiftCode); // append the pre-lift codes //do the lift sb.Append("G1 Z" + String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)) + " F" + feedrate + " (Lift) \r\n"); sb.Append(sf.m_config.PostLiftCode); // append the post-lift codes // move back from the lift sb.Append("G1 Z" + String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir * -1)) + " F" + feedrate + " (End Lift) \r\n"); // add a delay for the lift sequence and the pre/post lift codes to execute sb.Append(blankdelay); // this move is moved to the end, so the first layer doesn't try to move up sb.Append("G1 Z" + String.Format("{0:0.00000}", (zdist * zdir)) + " F" + feedrate + "\r\n"); sb.Append(raisetime); } //append the footer sb.Append(sf.m_config.FooterCode); gcode = sb.ToString(); GCodeFile gc = new GCodeFile(gcode); return gc; }
private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf) { try { if (InvokeRequired) { BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers, sf); })); } else { switch (ev) { case Slicer.eSliceEvent.eSliceStarted: Text = ""; break; case Slicer.eSliceEvent.eSliceCompleted: //show the gcode Text = UVDLPApp.Instance().m_gcode.RawGCode; break; } } } catch (Exception ex) { DebugLogger.Instance().LogError(ex.Message); } }
private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf) { try { if (InvokeRequired) { BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers, sf); })); } else { switch (ev) { case Slicer.eSliceEvent.eSliceStarted: break; case Slicer.eSliceEvent.eLayerSliced: break; case Slicer.eSliceEvent.eSliceCompleted: SetNumLayers(totallayers); break; } } } catch (Exception ex) { DebugLogger.Instance().LogError(ex.Message); } }
/* This is the main function to generate gcode files for the * already sliced model */ public static GCodeFile Generate(SliceFile sf, MachineConfig pi) { String gcode; StringBuilder sb = new StringBuilder(); PreProcessor pp = PreparePreprocessor(sf, pi); double zdist = 0.0; // double feedrate = pi.ZMaxFeedrate; // 10mm/min double liftfeed = sf.m_config.liftfeedrate; double retractfeed = sf.m_config.liftretractrate; double zdir = 1.0; // assume a bottom up machine int numbottom = sf.m_config.numfirstlayers; if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down) { zdir = -1.0;// top down machine, reverse the z direction } pp.SetVar("$ZDir", zdir); // append the build parameters as reference sb.Append(sf.m_config.ToString()); sb.Append(";Number of Slices = " + sf.NumSlices.ToString() + "\r\n"); sb.Append(pi.ToString());//add the machine build parameters string // append the header sb.Append(pp.Process(sf.m_config.HeaderCode)); zdist = sf.m_config.ZThick; String firstlayerdelay = ";<Delay> " + sf.m_config.firstlayertime_ms + " \r\n"; String layerdelay = ";<Delay> " + sf.m_config.layertime_ms + " \r\n"; String blankdelay = ";<Delay> " + sf.m_config.blanktime_ms + " \r\n"; String preSliceGCode = pp.Process(sf.m_config.PreSliceCode); String LiftGCode = pp.Process(sf.m_config.LiftCode); for (int c = 0; c < sf.NumSlices; c++) { sb.Append(preSliceGCode);//add in the pre-slice code // this is the marker the BuildManager uses to display the correct slice sb.Append(";<Slice> " + c + " \r\n"); // add a pause for the UV resin to be set using this image if (c < numbottom)// check for the bottom layers { sb.Append(firstlayerdelay); } else { sb.Append(layerdelay); } sb.Append(";<Slice> Blank \r\n"); // show the blank layer sb.Append(LiftGCode); // append the pre-lift codes } //append the footer sb.Append(pp.Process(sf.m_config.FooterCode)); gcode = sb.ToString(); GCodeFile gc = new GCodeFile(gcode); return gc; }
/* GCode Process for building 3d DVP UV objects * <Build Start> * <Slicing Comments> comments containing the slicing and building parameters * <Header Code> start.gcode - commands from this * file are inserted, they contain whatever intiailization sequences are need to initialize the machine * at this point, the build tray is in position to start printing a layer * <Layer Start> * Display the correct image slice for the current layer * Delay for <Layertime> to expose the UV resin * <Layer End> */ // here we prepare the gcode preprocessor and fill all nessesary variables protected static PreProcessor PreparePreprocessor(SliceFile sf, MachineConfig pi) { PreProcessor pp = new PreProcessor(); pp.SetVar("$LayerThickness", sf.m_config.ZThick); // the thickenss of the layer in mm pp.SetVar("$ZLiftDist", sf.m_config.liftdistance); // how far we're lifting pp.SetVar("$ZLiftRate", sf.m_config.liftfeedrate); // the rate at which we're lifting pp.SetVar("$ZRetractRate", sf.m_config.liftretractrate); // how fast we'r retracting pp.SetVar("$SlideTiltVal", sf.m_config.slidetiltval); // any used slide / tilt value on the x axis pp.SetVar("$BlankTime", sf.m_config.blanktime_ms); // how long to show the blank in ms pp.SetVar("$LayerTime", sf.m_config.layertime_ms); // total delay for a layer for gcode commands to complete - not including expusre time pp.SetVar("$FirstLayerTime", sf.m_config.firstlayertime_ms); // time to expose the first layers in ms pp.SetVar("$NumFirstLayers", sf.m_config.numfirstlayers); // number of first layers return pp; }
/// <summary> /// Loads a model, adds it to the 3d engine to be shown, and raises an app event /// </summary> /// <param name="filename"></param> /// <returns></returns> public bool LoadModel(String filename) { try { ModelLoader ml = new ModelLoader(); List<Object3d> objs = ml.Load(filename); if (objs != null) { foreach (Object3d obj in objs) { obj.CenterOnPlatform(); m_engine3d.AddObject(obj); m_undoer.SaveAddition(obj); SelectedObject = obj; } UVDLPApp.Instance().m_engine3d.UpdateLists(); m_slicefile = null; // the slice file is not longer current RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename); //now try to load the gcode file String gcodefile = Path.GetFileNameWithoutExtension(filename) + ".gcode"; String gcodepath = SliceFile.GetSliceFilePath(filename); String gpath = gcodepath + UVDLPApp.m_pathsep + gcodefile; if (File.Exists(gpath)) { LoadGCode(gpath); } else // read the gcode from the zip file { String zpath = gcodepath + ".zip"; if(File.Exists(zpath)) // make sure the file exists before we try to read it { Stream s = Utility.ReadFromZip(zpath, gcodefile); if(s != null) { s.Seek(0, 0); // go to the beginning of the stream byte []array = Utility.ReadFully(s); string gc = System.Text.Encoding.ASCII.GetString(array); m_gcode = new GCodeFile(gc); RaiseAppEvent(eAppEvent.eGCodeLoaded, "GCode Loaded " + gcodefile); } else { DebugLogger.Instance().LogError("Could not load GCode from Zip " + zpath); } } } if(m_gcode !=null) { int xres, yres, numslices; xres = m_gcode.GetVar("Projector X Res"); yres = m_gcode.GetVar("Projector Y Res"); numslices = m_gcode.GetVar("Number of Slices"); m_slicefile = new SliceFile(xres,yres,numslices); m_slicefile.modelname = SelectedObject.m_fullname; m_slicefile.m_config = null; //this can be null if we're loading it... RaiseAppEvent(eAppEvent.eSlicedLoaded, "SliceFile Created"); } } else { RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load"); } return (objs != null); } catch (Exception ex) { DebugLogger.Instance().LogRecord(ex.Message); return false; } }
void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf) { String path = ""; String fileName = ""; switch (ev) { case Slicer.eSliceEvent.eSliceStarted: break; case Slicer.eSliceEvent.eLayerSliced: break; case Slicer.eSliceEvent.eSliceCompleted: m_slicefile = sf; //generate the GCode m_gcode = GCodeGenerator.Generate(m_slicefile, m_printerinfo); path = SliceFile.GetSliceFilePath(m_slicefile.modelname); fileName = Path.GetFileNameWithoutExtension(m_slicefile.modelname) + ".gcode"; //see if we're exporting this to a zip file if (sf.m_config.m_exportopt.Contains("ZIP")) { // open the existing zip file //store the gcode Stream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes (m_gcode.RawGCode)); String zpath = path + ".zip"; if (!Utility.StoreInZip(zpath, fileName, stream)) { DebugLogger.Instance().LogError("Could not store GCode in Zip " + zpath); } } else // or just to the disk { String sdn = path + UVDLPApp.m_pathsep + fileName; SaveGCode(sdn); } //save the slicer object for later too //save the slice file // UVDLPApp.Instance().m_slicefile.Save(path + UVDLPApp.m_pathsep + fn + ".sliced"); break; case Slicer.eSliceEvent.eSliceCancelled: DebugLogger.Instance().LogRecord("Slicing Cancelled"); break; } }
/// <summary> /// Loads a model, adds it to the 3d engine to be shown, and raises an app event /// </summary> /// <param name="filename"></param> /// <returns></returns> public bool LoadModel(String filename) { try { Object3d obj = new Object3d(); string ext = Path.GetExtension(filename); bool ret = false; ext = ext.ToLower(); if (ext.Equals(".dxf")) { ret = obj.LoadDXF(filename); } if (ext.Equals(".stl")) { ret = obj.LoadSTL(filename); } if (ext.Equals(".obj")) { ret = obj.LoadObjFile(filename); } if (ext.Equals(".3ds")) { ret = obj.Load3ds(filename); } if (ret == true) { m_engine3d.AddObject(obj); m_selectedobject = obj; m_slicefile = null; // the slice file is not longer current RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded"); } else { RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load"); } return ret; } catch (Exception ex) { DebugLogger.Instance().LogRecord(ex.Message); return false; } }
// This function is called to start the print job public void StartPrint(SliceFile sf, GCodeFile gcode) { if (m_printing) // already printing return; if (sf == null) { DebugLogger.Instance().LogRecord("No slice file, build cannot start"); RaiseStatusEvent(ePrintStat.ePrintCancelled); return; } if (gcode == null) { DebugLogger.Instance().LogRecord("No gcode file, build cannot start"); RaiseStatusEvent(ePrintStat.ePrintCancelled); return; } // we really need to map onto the events of the PrinterInterface to determine // important stuff like current z position, HBP temp, etc... m_printing = true; m_sf = sf; // set the slicefile for rendering m_gcode = gcode; // set the file m_state = STATE_START; // set the state machine as started m_runthread = new Thread(new ThreadStart(BuildThread)); m_running = true; m_runthread.Start(); }
/// <summary> /// This is the adaptive support generation, it should automatically /// detect overhangs and generate supports acordingly /// </summary> public void GenerateAdaptive2() { // iterate through all the layers starting from z=0 // slice all layers // split each layer into non overlapping polygons // check each polygon to see if it is completely overhangs in the air, or partially // supported by previous layers. // for complete overhangs always create supports // for partialy supported polygons, generate supports only if there is no other // support in the vicinity 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 new supports List<Object3d> lstsupports = new List<Object3d>(); // final list of supports List<SupportLocation> supLocs = new List<SupportLocation>(); // temporary list of support locations. int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config); float zlev = 0.0f; int hxres = config.xres / 2; int hyres = config.yres / 2; int npix = config.xres * config.yres; int[] lbm = new int[npix]; // current slice int[] lbmz = new int[npix]; // z buffer bool[] lbms = new bool[npix]; // support map int p; for (p = 0; p < npix; p++) { lbmz[p] = 0; lbms[p] = false; } Bitmap bm = new Bitmap(config.xres, config.yres, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // working bitmap Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor; m_supportgap = (int)(m_sc.mingap * config.dpmmX); m_asp.lbm = lbm; m_asp.lbms = lbms; m_asp.lbmz = lbmz; m_asp.searchmap = new int[npix]; m_asp.xres = config.xres; m_asp.yres = config.yres; m_asp.mingap = m_supportgap; 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) || (sl.m_segments == null) || (sl.m_segments.Count == 0)) continue; sl.Optimize();// find loops using (Graphics gfx = Graphics.FromImage(bm)) gfx.Clear(Color.Transparent); //render current slice UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.FromArgb((0xFF << 24) | c); sl.RenderSlice(config, ref bm); BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Marshal.Copy(data.Scan0, lbm, 0, lbm.Length); for (p = 0; p < npix; p++) lbm[p] &= 0xFFFFFF; bm.UnlockBits(data); if (c > 0) { if (m_sc.eSupType == SupportConfig.eAUTOSUPPORTTYPE.eADAPTIVE) ProcessSlice(lbm, lbmz, lbms, config.xres, config.yres, supLocs); else ProcessSlice2(supLocs); } // add slice to zbuffer bitmap for (p = 0; p < npix; p++) if (lbm[p] != 0) lbmz[p] = lbm[p]; } UVDLPApp.Instance().m_appconfig.m_foregroundcolor = savecol; int scnt = 0; foreach (SupportLocation spl in supLocs) { float px = (float)(spl.x - hxres) / (float)config.dpmmX; float py = (float)(spl.y - hyres) / (float)config.dpmmY; float pz = (float)(spl.ztop) * (float)config.ZThick; AddNewSupport(px, py, pz, scnt++, GetSupportParrent(px,py,pz), lstsupports); } RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports); m_generating = false; } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } }
// This function is called to start the print job public void StartPrint(SliceFile sf, GCodeFile gcode, bool snippet = false) { //late init of callback handler if (callbackinited == false) { UVDLPApp.Instance().m_callbackhandler.RegisterCallback("DisplayDone", DisplayDone, null, "Indicates when the display device is done with the current slice"); callbackinited = true; } m_runningsnippet = snippet; if (m_printing) // already printing return; //make sure to reset these m_pause_request = false; //m_cancel_request = false; m_printing = true; m_buildstarttime = new DateTime(); m_buildstarttime = DateTime.Now; estimatedbuildtime = EstimateBuildTime(gcode); StartBuildTimer(); m_sf = sf; // set the slicefile for rendering m_gcode = gcode; // set the file m_state = STATE_START; // set the state machine as started m_runthread = new Thread(new ThreadStart(BuildThread)); m_running = true; m_runthread.Start(); }
void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf) { // String path = ""; // String fileName = ""; switch (ev) { case Slicer.eSliceEvent.eSliceStarted: break; case Slicer.eSliceEvent.eLayerSliced: break; case Slicer.eSliceEvent.eSliceCompleted: // this all needs to be changed.... m_slicefile = sf; //generate the GCode m_gcode = GCodeGenerator.Generate(m_slicefile, m_printerinfo); //we only need the file name of the gcode if we're saving it somewhere... //see if we're exporting this to a zip file //if (sf.m_config.m_exportopt.Contains("ZIP") && sf.m_config.export) if (sf.m_config.export) { // open the existing scene file //store the gcode MemoryStream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(m_gcode.RawGCode)); String gcn = Path.GetFileNameWithoutExtension(UVDLPApp.Instance().SceneFileName) + ".gcode"; //SceneFile.Instance().RemoveExistingGCode(UVDLPApp.Instance().SceneFileName); SceneFile.Instance().RemoveResourcesFromFile(UVDLPApp.Instance().SceneFileName, "GCode", ".gcode"); SceneFile.Instance().AddGCodeToFile(UVDLPApp.Instance().SceneFileName, stream, gcn); } //save the slicer object for later too //save the slice file // UVDLPApp.Instance().m_slicefile.Save(path + UVDLPApp.m_pathsep + fn + ".sliced"); break; case Slicer.eSliceEvent.eSliceCancelled: DebugLogger.Instance().LogRecord("Slicing Cancelled"); break; } }
// this function takes the object, the slicing parameters, // and the output directory. it generates the object slices // and saves them in the directory public SliceFile Slice(SliceBuildConfig sp, Object3d obj, String outdir) { m_obj = obj; m_cancel = false; // create new slice file m_sf = new SliceFile(sp); m_slicethread = new Thread(new ThreadStart(slicefunc)); m_slicethread.Start(); isslicing = true; return m_sf; }
// standard scene slicing // this function takes the object, the slicing parameters, // and the output directory. it generates the object slices // and saves them in the directory public SliceFile Slice(SliceBuildConfig sp)//, Object3d obj) { // create new slice file m_sf = new SliceFile(sp); m_sf.m_modeltype = Slicing.SliceFile.ModelType.eScene; if (sp.export == false) { m_sf.m_mode = SliceFile.SFMode.eImmediate; } m_slicethread = new Thread(new ThreadStart(slicefunc)); m_slicethread.Start(); isslicing = true; return m_sf; }
/* GCode Process for building 3d DVP UV objects * <Build Start> * <Slicing Comments> comments containing the slicing and building parameters * <Header Code> start.gcode - commands from this * file are inserted, they contain whatever intiailization sequences are need to initialize the machine * at this point, the build tray is in position to start printing a layer * <Layer Start> * Display the correct image slice for the current layer * Delay for <Layertime> to expose the UV resin * <Layer End> */ /* This is the main function to generate gcode files for the * already sliced model */ public static GCodeFile Generate(SliceFile sf, MachineConfig pi) { String gcode; StringBuilder sb = new StringBuilder(); double zdist = 0.0; // double feedrate = pi.ZMaxFeedrate; // 10mm/min double liftfeed = sf.m_config.liftfeedrate; double retractfeed = sf.m_config.liftretractrate; double zdir = 1.0; // assume a bottom up machine int numbottom = sf.m_config.numfirstlayers; if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down) { zdir = -1.0;// top down machine, reverse the z direction } // append the build parameters as reference sb.Append(sf.m_config.ToString()); sb.Append(";(Number of Slices = " + sf.NumSlices.ToString() + ")\r\n"); sb.Append(pi.ToString());//add the machine build parameters string // append the header sb.Append(sf.m_config.HeaderCode); zdist = sf.m_config.ZThick; String firstlayerdelay = ";(<Delay> " + sf.m_config.firstlayertime_ms + " )\r\n"; String layerdelay = ";(<Delay> " + sf.m_config.layertime_ms + " )\r\n"; String blankdelay = ";(<Delay> " + sf.m_config.blanktime_ms + " )\r\n"; String tmpZU = String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)).Replace(',', '.'); String tmpZD = String.Format("{0:0.00000}", ((sf.m_config.liftdistance - zdist) * zdir * -1)).Replace(',', '.'); String tmpX1 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval)).Replace(',', '.'); String tmpX2 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval * -1)).Replace(',', '.'); for (int c = 0; c < sf.NumSlices; c++) { sb.Append(sf.m_config.PreSliceCode);//add in the pre-slice code // this is the marker the BuildManager uses to display the correct slice sb.Append(";(<Slice> " + c + " )\r\n"); // add a pause for the UV resin to be set using this image if (c < numbottom)// check for the bottom layers { sb.Append(firstlayerdelay); } else { sb.Append(layerdelay); } sb.Append(";(<Slice> Blank )\r\n"); // show the blank layer sb.Append(sf.m_config.PreLiftCode); // append the pre-lift codes // I put the following two lines out of the loop to reduce calculationTime //String tmpZU = String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)).Replace(',', '.'); //String tmpZD = String.Format("{0:0.00000}", ((sf.m_config.liftdistance - zdist) * zdir * -1)).Replace(',', '.'); if (sf.m_config.usemainliftgcode == true) // if you want to use the GCode from the MainLiftGCode-Tab { sb.Append(sf.m_config.MainLiftCode); } else if (sf.m_config.slidetiltval == 0.0) // tilt/slide is not used here { sb.Append("G1 Z" + tmpZU + " F" + liftfeed + " ;(Lift) \r\n"); sb.Append("G1 Z" + tmpZD + " F" + retractfeed + " ;(End Lift) \r\n"); } else // tilt/slide has a value, so it is used { // I put the following two lines out of the loop to reduce calculationTime // format the X slide/tilt value //String tmpX1 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval)).Replace(',', '.'); //String tmpX2 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval * -1)).Replace(',', '.'); sb.Append("G1 X" + tmpX1 + " Z" + tmpZU + " F" + liftfeed + " ;(Lift) \r\n"); sb.Append("G1 X" + tmpX2 + " Z" + tmpZD + " F" + retractfeed + " ;(End Lift) \r\n"); } // add a delay for the lift sequence and the pre/post lift codes to execute sb.Append(blankdelay); // append the post-lift codes sb.Append(sf.m_config.PostLiftCode); } //append the footer sb.Append(sf.m_config.FooterCode); gcode = sb.ToString(); GCodeFile gc = new GCodeFile(gcode); return gc; }
/// <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 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 } 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++) { //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(); float lz = center.z; AddNewSupport(center.x, center.y, center.z, scnt++, null, lstsupports); //region.ply.m_derived. /*s.Create(null,(float)m_sc.fbrad, (float)m_sc.ftrad, (float)m_sc.hbrad, (float)m_sc.htrad, lz * .2f, lz * .6f, lz * .2f, 11); s.Translate((float)center.x, (float)center.y, 0); s.Name = "Support " + scnt; s.SetColor(Color.Yellow); scnt++; lstsupports.Add(s); RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eSupportGenerated, s.Name, s); */ } RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports); m_generating = false; } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } }
public bool LoadModel(String filename) { try { Object3d obj = new Object3d(); if (obj.LoadSTL(filename) == false) { return false; } else { m_engine3d.AddObject(obj); m_selectedobject = obj; m_slicefile = null; // the slice file is not longer current } RaiseAppEvent(eAppEvent.eModelLoaded, "Model Loaded"); return true; } catch (Exception ex) { DebugLogger.Instance().LogRecord(ex.Message); return false; } }
/* This is the main function to generate gcode files for the * already sliced model */ public static GCodeFile Generate(SliceFile sf, MachineConfig pi) { String gcode; StringBuilder sb = new StringBuilder(); PreProcessor pp = PreparePreprocessor(sf, pi); double zdist = 0.0; // double feedrate = pi.ZMaxFeedrate; // 10mm/min double liftfeed = sf.m_config.liftfeedrate; double bottomliftfeed = sf.m_config.bottomliftfeedrate; double retractfeed = sf.m_config.liftretractrate; double zdir = 1.0; // assume a bottom up machine int numbottom = sf.m_config.numfirstlayers; if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down) { zdir = -1.0;// top down machine, reverse the z direction } pp.SetVar("$ZDir", zdir); // append the build parameters as reference sb.Append(sf.m_config.ToString()); sb.Append(";Number of Slices = " + sf.NumSlices.ToString() + "\r\n"); sb.Append(pi.ToString());//add the machine build parameters string // append the header sb.Append(pp.Process(sf.m_config.HeaderCode)); zdist = sf.m_config.ZThick; String firstlayerdelay = ";<Delay> " + sf.m_config.firstlayertime_ms + " \r\n"; String layerdelay = ";<Delay> " + sf.m_config.layertime_ms + " \r\n"; String blankdelay = ";<Delay> " + sf.m_config.blanktime_ms + " \r\n"; String preSliceGCode = pp.Process(sf.m_config.PreSliceCode); String LiftGCode = pp.Process(sf.m_config.LiftCode); int numslices = sf.NumSlices; if (sf.m_modeltype == SliceFile.ModelType.eResinTest1) numslices -= 10; // for a per-slice basis, we're going to re-evaluate the prelift and lift gcode // doing this will allow us to have per-slice determinations based on slice index. int c; for (c = 0; c < numslices; c++) { pp.SetVar("$CURSLICE", c); preSliceGCode = pp.Process(sf.m_config.PreSliceCode); //pp.SetVar("$CURSLICE", c); sb.Append(preSliceGCode);//add in the pre-slice code // this is the marker the BuildManager uses to display the correct slice sb.Append(";<Slice> " + c + " \r\n"); // add a pause for the UV resin to be set using this image if (c < numbottom)// check for the bottom layers { sb.Append(firstlayerdelay); } else { sb.Append(layerdelay); } sb.Append(";<Slice> Blank \r\n"); // show the blank layer LiftGCode = pp.Process(sf.m_config.LiftCode); // re-run the lift code sb.Append(LiftGCode); // append the pre-lift codes } // special ending on resin test model slicing if (sf.m_modeltype == SliceFile.ModelType.eResinTest1) { for (; c < sf.NumSlices; c++) { sb.Append(";<Slice> " + c + " \r\n"); // add a pause for the UV resin to be set using this image if (c == sf.NumSlices -1) // set minimus exposure time on final layer sb.Append(";<Delay> " + sf.m_config.minExposure + " \r\n"); else sb.Append(";<Delay> " + sf.m_config.exposureStep + " \r\n"); } sb.Append(";<Slice> Blank \r\n"); // show the blank layer LiftGCode = pp.Process(sf.m_config.LiftCode); // re-run the lift code sb.Append(LiftGCode); // append the pre-lift codes } //append the footer sb.Append(pp.Process(sf.m_config.FooterCode)); gcode = sb.ToString(); GCodeFile gc = new GCodeFile(gcode); return gc; }
//, Object3d obj) // slicing of special objects. this is done in immediate mode only. no thread needed public SliceFile Slice(SliceBuildConfig sp, SliceFile.ModelType modeltype) { int numslices = 0; string scenename = ""; switch (modeltype) { case SliceFile.ModelType.eScene: return Slice(sp); //break; case SliceFile.ModelType.eResinTest1: numslices = (int)(7.0 / sp.ZThick); scenename = "Test Model V1"; break; } m_sf = new SliceFile(sp); m_sf.m_modeltype = modeltype; m_sf.m_mode = SliceFile.SFMode.eImmediate; m_sf.NumSlices = numslices; SliceStarted(scenename, numslices); DebugLogger.Instance().LogRecord("Test model slicing started"); SliceCompleted(scenename, 0, numslices); return m_sf; }
/* GCode Process for building 3d DVP UV objects * <Build Start> * <Slicing Comments> comments containing the slicing and building parameters * <Header Code> start.gcode - commands from this * file are inserted, they contain whatever intiailization sequences are need to initialize the machine * at this point, the build tray is in position to start printing a layer * <Layer Start> * Display the correct image slice for the current layer * Delay for <Layertime> to expose the UV resin * <Layer End> */ // here we prepare the gcode preprocessor and fill all nessesary variables protected static PreProcessor PreparePreprocessor(SliceFile sf, MachineConfig pi) { PreProcessor pp = new PreProcessor(); pp.SetVar("$LayerThickness", sf.m_config.ZThick); pp.SetVar("$ZLiftDist", sf.m_config.liftdistance); pp.SetVar("$ZLiftRate", sf.m_config.liftfeedrate); pp.SetVar("$ZRetractRate", sf.m_config.liftretractrate); pp.SetVar("$SlideTiltVal", sf.m_config.slidetiltval); pp.SetVar("$BlankTime", sf.m_config.blanktime_ms); pp.SetVar("$LayerTime", sf.m_config.layertime_ms); pp.SetVar("$FirstLayerTime", sf.m_config.firstlayertime_ms); return pp; }
//, Object3d obj) // this function takes the object, the slicing parameters, // and the output directory. it generates the object slices // and saves them in the directory public SliceFile Slice(SliceBuildConfig sp) { //m_obj = obj; m_cancel = false; // create new slice file m_sf = new SliceFile(sp); if (sp.export == false) { m_sf.m_mode = SliceFile.SFMode.eImmediate; } m_slicethread = new Thread(new ThreadStart(slicefunc)); m_slicethread.Start(); isslicing = true; return m_sf; }
public override string Export(Stream stream, string filename) { m_stream = stream; if ((m_name == null) || (m_name.Length == 0)) m_name = Path.GetFileNameWithoutExtension(filename); if ((m_description == null) || (m_description.Length == 0)) m_description = m_name; try { ReportStart(); SliceBuildConfig config = UVDLPApp.Instance().m_buildparms; config.UpdateFrom(UVDLPApp.Instance().m_printerinfo); // make sure we've got the correct display size and PixPerMM values // write header WriteString("1"); // version WriteString(m_name); // scene name WriteString(m_description); // scene description WriteDouble(1 / config.dpmmX); // pixel size in mm WriteDouble(config.ZThick); // slice thickness WriteInt32(0); // base standoff layers (?) WriteInt32(0); // Number of base offset layers where extents are filled (?) WriteString("Reserved3"); WriteString("Reserved2"); WriteString("Reserved1"); // write slices int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config); WriteInt32(numslices); float zlev = (float)(config.ZThick * 0.5); int npix = config.xres * config.yres; int[] lbm = new int[npix]; // current slice int p; //Bitmap bm = new Bitmap(config.xres, config.yres, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // working bitmap //Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor; 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 } for (int c = 0; c < numslices; c++) { //bool layerneedssupport = false; if (CancelExport) { return "Info|Export operation canceled"; } ReportProgress(c * 100 / numslices); /*Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev); zlev += (float)config.ZThick; if ((sl == null) || (sl.m_segments == null) || (sl.m_segments.Count == 0)) continue; sl.Optimize();// find loops using (Graphics gfx = Graphics.FromImage(bm)) gfx.Clear(Color.Transparent); //render current slice UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.White; sl.RenderSlice(config, ref bm);*/ Bitmap bm = UVDLPApp.Instance().m_slicer.SliceImmediate(zlev); zlev += (float)config.ZThick; BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Marshal.Copy(data.Scan0, lbm, 0, lbm.Length); for (p = 0; p < npix; p++) lbm[p] &= 0xFFFFFF; bm.UnlockBits(data); CrushSlice(lbm, config.xres, config.yres); } // write supports (currently not handled) WriteInt32(0); // zero supports } catch (Exception ex) { DebugLogger.Instance().LogError(ex); return "Error|Export terminated unexpectedly"; } return "Export|Export completed successfully"; }
// This function is called to start the print job public void StartPrint(SliceFile sf, GCodeFile gcode) { if (m_printing) // already printing return; m_printing = true; m_buildstarttime = new DateTime(); m_buildstarttime = DateTime.Now; estimatedbuildtime = EstimateBuildTime(gcode); StartBuildTimer(); m_sf = sf; // set the slicefile for rendering m_gcode = gcode; // set the file m_state = STATE_START; // set the state machine as started m_runthread = new Thread(new ThreadStart(BuildThread)); m_running = true; m_runthread.Start(); }
// This function is called to start the print job public void StartPrint(SliceFile sf, GCodeFile gcode, bool snippet = false) { m_runningsnippet = snippet; if (m_printing) // already printing return; //make sure to reset these m_pause_request = false; //m_cancel_request = false; m_printing = true; m_buildstarttime = new DateTime(); m_buildstarttime = DateTime.Now; estimatedbuildtime = EstimateBuildTime(gcode); StartBuildTimer(); m_sf = sf; // set the slicefile for rendering m_gcode = gcode; // set the file m_state = STATE_START; // set the state machine as started m_runthread = new Thread(new ThreadStart(BuildThread)); m_running = true; m_runthread.Start(); }
private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf) { try { if (InvokeRequired) { BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers,sf); })); } else { switch (ev) { case Slicer.eSliceEvent.eSliceStarted: SetMainMessage("Slicing Started"); break; case Slicer.eSliceEvent.eLayerSliced: break; case Slicer.eSliceEvent.eSliceCompleted: //show the gcode txtGCode.Text = UVDLPApp.Instance().m_gcode.RawGCode; SetVScrollMax(totallayers); SetMainMessage("Slicing Completed"); String timeest = BuildManager.EstimateBuildTime(UVDLPApp.Instance().m_gcode); SetTimeMessage("Estimated Build Time: " + timeest); //show the slice in the slice view ViewLayer(0, null, BuildManager.SLICE_NORMAL); break; } } } catch (Exception ex) { DebugLogger.Instance().LogError(ex.Message); } }
/// <summary> /// Loads a model, adds it to the 3d engine to be shown, and raises an app event /// </summary> /// <param name="filename"></param> /// <returns></returns> public bool LoadModel(String filename) { try { ModelLoader ml = new ModelLoader(); List<Object3d> objs = ml.Load(filename); if (objs != null) { foreach (Object3d obj in objs) { obj.CenterOnPlatform(); m_engine3d.AddObject(obj); m_undoer.SaveAddition(obj); SelectedObject = obj; } UVDLPApp.Instance().m_engine3d.UpdateLists(); m_slicefile = null; // the slice file is not longer current RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename); } else { RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load"); } return (objs != null); } catch (Exception ex) { DebugLogger.Instance().LogRecord(ex.Message); return false; } }
/// <summary> /// Loads a model, adds it to the 3d engine to be shown, and raises an app event /// </summary> /// <param name="filename"></param> /// <returns></returns> public bool LoadModel(String filename) { try { ModelLoader ml = new ModelLoader(); List<Object3d> objs = ml.Load(filename); if (objs != null) { foreach (Object3d obj in objs) { obj.CenterOnPlatform(); m_engine3d.AddObject(obj); m_undoer.SaveAddition(obj); SelectedObject = obj; //test code to create a preview, this should definitely go somewhere else /*PreviewGenerator pg = new PreviewGenerator(); Bitmap preview = pg.GeneratePreview(512, 512, obj); if(preview !=null) preview.Save(UVDLPApp.Instance().m_apppath + "\\testpreview.png");*/ } UVDLPApp.Instance().m_engine3d.UpdateLists(); m_slicefile = null; // the slice file is not longer current RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename); } else { RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load"); } return (objs != null); } catch (Exception ex) { DebugLogger.Instance().LogRecord(ex.Message); return false; } }
/// <summary> /// This is called after the scene file is loaded /// It will also load the gcode file and slicing profile / vector slices /// </summary> public void PostLoadScene() { m_gcode = SceneFile.Instance().LoadGCodeFromScene(SceneFileName); if (m_gcode == null) { m_gcode = new GCodeFile(""); // create empty file } RaiseAppEvent(eAppEvent.eGCodeLoaded, "GCode Loaded "); SceneFile.Instance().LoadSliceProfileFromScene(SceneFileName); m_slicefile = new SliceFile(m_buildparms); m_slicefile.m_mode = SliceFile.SFMode.eLoaded; m_slicer.SliceFile = m_slicefile; //set the number of slices m_slicefile.NumSlices = m_slicer.GetNumberOfSlices(m_buildparms); RaiseAppEvent(eAppEvent.eSliceProfileChanged, "Slice Profile loaded"); RaiseAppEvent(eAppEvent.eSlicedLoaded, "Slice Profile loaded"); }