public void saveModel(String newfilename) throws IOException { FileWriter fwr = new FileWriter(newfilename); BufferedWriter gcwr = new BufferedWriter(fwr); for (GCode gc : gcodes) { gcwr.write(gc.getCodeline().toString()); // gcwr.write("\n"); } gcwr.close(); fwr.close(); }
public String getModelComments() { StringBuilder buf = new StringBuilder(500); buf.append("--------- Slicer Comments------------\n"); int max = 500; // max to avoid OOM for (GCode gCode : gcodes) { // Ignore comments behind gcodes if (max > 0 && gCode.isComment()) { // System.out.println(gCode.getComment()); buf.append(gCode.getComment()); buf.append(Constants.newlinec); max--; } } return buf.toString(); }
/** * Guess diameter 1) user defined environment variable 2) comments in GCODE file 3) Fallback to * some very rough calculation * * @return diameter */ private float guessDiameter() { // Read user defined environment variable if exists try { String dia = System.getenv("FILAMENT_DIAMETER"); if (dia != null) { // System.out.println("Use env value FILAMENT_DIAMETER="+dia); return Float.parseFloat(dia); } } catch (NumberFormatException e1) { } // get diameter from comments in gcode file try { GCodeStore codes = getGcodes(); for (GCode gCode : codes) { // Ignore comments behind gcodes if (gCode.isComment()) { // System.out.println("COMMENT"+gCode.getComment()); if (gCode.getComment().matches(".*FILAMENT_DIAMETER\\s=.*")) { // SLICER // System.out.println("MATCHES:"+gCode.getComment()); String[] res = gCode.getComment().split("="); return Float.parseFloat(res[1]); } else if (gCode.getComment().matches(".*FILAMENT_DIAMETER_.*")) { // SKEINFORGE // System.out.println("MATCHES:"+gCode.getComment()); String[] res = gCode.getComment().split("[:<]"); return Float.parseFloat(res[2]); } } } } catch (Exception e) { // Comment parsing failed } // System.err.println("Failed to parse GCODE comments for filament diameter. Fallback to // guessing."); // Fallback ... no comments found isguessed = true; // Tried many formulars but there is no good way to guess the diameter (too many unknowns) // float exRadius = getAvgLayerHeight() / 2; float WOT = 2.1f; // Assume a wide over thickness value of ~2.1 (heavily depends on nozzel size) double extrArea = exRadius * (exRadius * WOT) * Math.PI; // Fläche extruded mm2 double menge = extrArea * getDistance(); double sizeArea = menge / getExtrusion(); double guessedDia = Math.sqrt(sizeArea / Math.PI) * 2; // System.out.println("Extr menge mm3:"+menge/1000+" Estimate dia:"+guessedDia); // Either take 1.75 or 3mm if (guessedDia > 2.45f) { return 3; } else if (guessedDia < 2.05f) { return 1.75f; } // use 3 System.out.println( "Unable to detect diameter - Fallback to 3mm.\nPlease set environment variable FILAMENT_DIAMETER"); return 3; }
/** * Main method to walk through the GCODES and analyze them. * * @return */ public void analyze() { Layer currLayer = startLayer(0, null); Layer lastprinted = currLayer; // Current Positions & Speed float xpos = 0; Position currpos = new Position(0, 0); float lastxpos = 0; float lastypos = 0; float lastzpos = 0; boolean pos_changed = false; float ypos = 0; float zpos = 0; float epos = 0; float f_old = 1000; float f_new = f_old; float bedtemp = 0, extemp = 0; boolean m101 = false; // BFB style extrusion float m108 = 0; // Bfb style extr. GCodeStore gcarr = getGcodes(); int gcnum = gcarr.size(); for (int ig = 0; ig < gcnum; ig++) { GCode gc = gcarr.get(ig); lastxpos = xpos; lastypos = ypos; lastzpos = zpos; // Update Speed if specified // TODO Clarify if default speed is the last used speed or not if (gc.isInitialized(Constants.F_MASK)) { if (!gc.isInitialized(Constants.X_MASK) && !gc.isInitialized(Constants.Y_MASK) && !gc.isInitialized(Constants.Z_MASK) || !ACCELERATION) { f_old = gc.getF(); // no movement no acceleration f_new = gc.getF(); // faccel is the same } else { f_new = gc.getF(); // acceleration } } if (gc.getGcode() == Constants.GCDEF.G1 || gc.getGcode() == Constants.GCDEF.G0 || gc.getGcode() == Constants.GCDEF.G2 || gc.getGcode() == Constants.GCDEF.G3) { if (currLayer.highidx - currLayer.lowidx < 5) { // only set layer temp, if not already printed too much currLayer.setBedtemp(bedtemp); currLayer.setExttemp(extemp); } // Detect Layer change and create new layers. if (gc.isInitialized(Constants.Z_MASK) && gc.getZ() != currLayer.getZPosition()) { // endLayer(currLayer); //finish old layer if (currLayer.isPrinted()) { lastprinted = currLayer; } else if (lastprinted != currLayer) { // Assume zlift // Append non printed layers to last printed one // Z-lift would otherwise cause thousands of layers // for (GCode gco : currLayer.getGcodes()) { // lastprinted.addGcodes(gco,ig); // } lastprinted.highidx = ig; // set high index to new index layercount--; layer.remove(currLayer); // Minor problem is that the beginning of a new layer is sometimes without extrusion // before the first z-lift // this leads to assigning this to the previous printed layer. } currLayer = startLayer(gc.getZ(), lastprinted); // Start new layer currLayer.setBedtemp(bedtemp); currLayer.setExttemp(extemp); } float move = 0; // Move G1 - X/Y at the same time if (gc.getGcode() == Constants.GCDEF.G2 || gc.getGcode() == Constants.GCDEF.G3) { // center I&J relative to x&y float cx = (xpos + gc.getIx()); float cy = (ypos + gc.getJy()); float newxpos = gc.isInitialized(Constants.X_MASK) ? gc.getX() : xpos; float newypos = gc.isInitialized(Constants.Y_MASK) ? gc.getY() : ypos; // triangle float bx = (newxpos - cx); float by = (newypos - cy); float ax = (xpos - cx); float ay = (ypos - cy); // Java drawarc is based on a bonding box // Left upper edge of the bounding box float xmove = Math.abs(cx - xpos); float ymove = Math.abs(cy - ypos); // assume a circle (no oval) float radius = ((float) Math.sqrt((xmove * xmove) + (ymove * ymove))); double angle1, angle2; // Calculate right angle if (gc.getGcode() == Constants.GCDEF.G2) { angle1 = Math.atan2(by, bx) * (180 / Math.PI); angle2 = Math.atan2(ay, ax) * (180 / Math.PI); } else { angle2 = Math.atan2(by, bx) * (180 / Math.PI); angle1 = Math.atan2(ay, ax) * (180 / Math.PI); } double angle = (int) (angle2 - angle1); xpos = newxpos; ypos = newypos; // Bogenlaenge move = (float) (Math.PI * radius * angle / 180); gc.setDistance(move); } else if (gc.isInitialized(Constants.X_MASK) && gc.isInitialized(Constants.Y_MASK)) { float xmove = Math.abs(xpos - gc.getX()); float ymove = Math.abs(ypos - gc.getY()); xpos = gc.getX(); ypos = gc.getY(); move = (float) Math.sqrt((xmove * xmove) + (ymove * ymove)); gc.setDistance(move); } else if (gc.isInitialized(Constants.X_MASK)) { move = Math.abs(xpos - gc.getX()); xpos = gc.getX(); gc.setDistance(move); } else if (gc.isInitialized(Constants.Y_MASK)) { move = Math.abs(ypos - gc.getY()); ypos = gc.getY(); gc.setDistance(move); } else if (gc.isInitialized(Constants.E_MASK)) { // Only E means we need to measure the time move = Math.abs(epos - gc.getE()); } else if (gc.isInitialized(Constants.Z_MASK)) { // Only Z means we need to measure the time // TODO if Z + others move together, Z might take longest. Need to add time move = Math.abs(zpos - gc.getZ()); } // update Z pos when Z changed if (gc.isInitialized(Constants.Z_MASK)) { zpos = gc.getZ(); } // Update epos and extrusion, not add time because the actual move time is already added if (gc.isInitialized(Constants.E_MASK)) { if (relativepos) { gc.setExtrusion(gc.getE()); epos = 0; } else { float oldepos = gc.getE(); gc.setExtrusion(gc.getE() - epos); epos = oldepos; } } else if (m101) { float extr = m108 / 60 * (move / (f_new / 60)); // only for direct drive extr. with r=5 // gc.setInitialized(Constants.E_MASK, extr); //commented out to avoid E to be send to the // printer gc.setExtrusion(extr); } if (useAcceleration) { // Calculate time with a linear acceleration if (f_new >= f_old) { // Assume sprinter _MAX_START_SPEED_UNITS_PER_SECOND {40.0,40.0,....} gc.setTimeAccel( move / (((Math.min(40 * 60, f_old) + f_new) / 2) / 60)); // set time with linear acceleration // System.out.println("F"+f_old+"FA"+f_new+"time"+gc.getTime()+"ACCEL: // "+(Math.abs(40-f_new)/gc.getTimeAccel())); } else { gc.setTimeAccel(move / ((f_old + f_new) / 2 / 60)); // set time with linear acceleration // System.out.println("F"+f_old+"FA"+f_new+" DEACCEL: // "+(Math.abs(f_old-f_new)/gc.getTimeAccel())); } } else { // Calculate time without acceleration gc.setTimeAccel(move / (f_new / 60)); // Set time w/o acceleration } f_old = f_new; // acceleration done. assign new speed // Calculate print size // if(gc.isInitialized(Constants.E_MASK) && gc.getE() > 0) { if ((gc.isExtruding() && gc.getDistance() != 0) || m101) { if (pos_changed) { // make sure that the start position is used for the boundary // calculation currLayer.addPosition(lastxpos, lastypos, lastzpos); } currLayer.addPosition(xpos, ypos, zpos); pos_changed = true; } } else if (gc.getGcode() == Constants.GCDEF.G28 || gc.getGcode() == Constants.GCDEF.G92) { // Initialize Axis if (gc.isInitialized(Constants.E_MASK)) epos = gc.getE(); if (gc.isInitialized(Constants.X_MASK)) xpos = gc.getX(); if (gc.isInitialized(Constants.Y_MASK)) ypos = gc.getY(); if (gc.isInitialized(Constants.Z_MASK)) zpos = gc.getZ(); } else if (gc.getGcode() == Constants.GCDEF.G91) { relativepos = true; } else if (gc.getGcode() == Constants.GCDEF.G90) { relativepos = false; } else if (gc.getGcode() == Constants.GCDEF.G20 || gc.getGcode() == Constants.GCDEF.G21) { // Assume that unit is only set once currLayer.setUnit(gc.getUnit()); } else if (gc.getGcode() == Constants.GCDEF.M101) { // bfb style gcode m101 = true; } else if (gc.getGcode() == Constants.GCDEF.M103) { m101 = false; } else if (gc.getGcode() == Constants.GCDEF.T0) { // extruders=Math.max(extruders, 1); } else if (gc.getGcode() == Constants.GCDEF.T1) { extruderCount = Math.max(extruderCount, 2); } else if (gc.getGcode() == Constants.GCDEF.T2) { extruderCount = Math.max(extruderCount, 3); } else if (gc.getGcode() == Constants.GCDEF.T3) { extruderCount = Math.max(extruderCount, 4); } else if (gc.getGcode() == Constants.GCDEF.T4) { extruderCount = Math.max(extruderCount, 5); } else if (gc.getGcode() == Constants.GCDEF.M218 || gc.getGcode() == Constants.GCDEF.G10) { float xoff = 0; float yoff = 0; if (gc.isInitialized(Constants.X_MASK)) xoff = gc.getX(); if (gc.isInitialized(Constants.Y_MASK)) yoff = gc.getY(); int toff = (int) gc.getR(); // T is stored in R field if (extruderOffset == null) extruderOffset = new Position[] {null, null, null, null, null}; // init for 5 extr. if (toff <= 4) { extruderOffset[toff] = new Position(xoff, yoff); } } else if (gc.getGcode() == Constants.GCDEF.M108) { if (gc.isInitialized(Constants.E_MASK)) m108 = gc.getE(); } else if (gc.isInitialized(Constants.SF_MASK)) { // update Fan if specified currLayer.setFanspeed((int) gc.getFanspeed()); } else if (gc.isInitialized(Constants.SE_MASK)) { // update Temperature if specified extemp = gc.getExtemp(); } else if (gc.isInitialized(Constants.SB_MASK)) { // Update Bed Temperature if specified bedtemp = gc.getBedtemp(); } currpos.updatePos(xpos, ypos); // reuse currposs obj, gcode just copies the floats gc.setCurrentPosition(currpos); // Add Gcode to Layer currLayer.addGcodes(gc, ig); } // System.out.println("Summarize Layers"); for (Layer closelayer : layer) { endLayer(closelayer); // finish old layer } // End last layer // endLayer(currLayer); }