/* * Created on May 1, 2006 * * Changed by Vik to reject polts of less than 0.05mm */ package org.reprap.geometry; import java.io.IOException; import javax.media.j3d.*; import org.reprap.Printer; import org.reprap.Attributes; import org.reprap.Preferences; import org.reprap.ReprapException; import org.reprap.geometry.polygons.*; import org.reprap.devices.pseudo.LinePrinter; import org.reprap.utilities.Debug; import org.reprap.geometry.Producer; /** * */ class segmentSpeeds { /** * */ public Rr2Point p1, p2, p3; /** * */ public double ca; /** * */ public boolean plotMiddle; /** * */ public boolean abandon; /** * @param before * @param now * @param after * @param fastLength */ public segmentSpeeds(Rr2Point before, Rr2Point now, Rr2Point after, double fastLength) { Rr2Point a = Rr2Point.sub(now, before); double amod = a.mod(); abandon = amod == 0; if(abandon) return; Rr2Point b = Rr2Point.sub(after, now); if(b.mod() == 0) ca = 0; else ca = Rr2Point.mul(a.norm(), b.norm()); plotMiddle = true; if(amod <= 2*fastLength) { fastLength = amod*0.5; plotMiddle = false; } a = a.norm(); p1 = Rr2Point.add(before, Rr2Point.mul(a, fastLength)); p2 = Rr2Point.add(p1, Rr2Point.mul(a, amod - 2*fastLength)); p3 = Rr2Point.add(p2, Rr2Point.mul(a, fastLength)); } int speed(int currentSpeed, double angFac) { double fac = (1 - 0.5*(1 + ca)*angFac); return LinePrinter.speedFix(currentSpeed, fac); } } /** * */ public class LayerProducer { /** * The shape of the object built so far under the current layer */ private BranchGroup lowerShell = null; /** * */ private Printer printer = null; /** * The polygons to infill */ private RrPolygonList hatchedPolygons = null; /** * The polygons to outline */ private RrPolygonList borderPolygons = null; /** * CSG representation of the polygons as input */ private RrCSGPolygonList csgP = null; /** * CSG representation of the polygons offset by the width of * the extruders */ RrCSGPolygonList offBorder = null; /** * CSG representation of the polygons offset by the factor of the * width of the extruders needed to lay down internal cross-hatching */ RrCSGPolygonList offHatch = null; /** * The height of the current layer */ private double z; /** * Counters use so that each material is plotted completely before * moving on to the next. */ private int commonBorder, commonHatch; /** * The clue is in the name... */ private int currentSpeed; /** * Count of how many up we are (the bottom is layer 0) */ private int layerNumber; /** * Record the end of each polygon as a clue where to start next */ private Rr2Point startNearHere = null; /** * Flag to prevent cyclic graphs going round forever */ private boolean beingDestroyed = false; /** * Destroy me and all that I point to */ public void destroy() { if(beingDestroyed) // Prevent infinite loop return; beingDestroyed = true; // Keep the lower shell - the graphics system is using it //lowerShell = null; // Keep the printer; that's needed for the next layer //printer = null; if(hatchedPolygons != null) hatchedPolygons.destroy(); hatchedPolygons = null; if(borderPolygons != null) borderPolygons.destroy(); borderPolygons = null; if(csgP != null) csgP.destroy(); csgP = null; if(offBorder != null) offBorder.destroy(); offBorder = null; if(offHatch != null) offHatch.destroy(); offHatch = null; if(startNearHere != null) startNearHere.destroy(); startNearHere = null; beingDestroyed = false; } /** * Destroy just me */ protected void finalize() throws Throwable { // Keep the lower shell - the graphics system is using it //lowerShell = null; // Keep the printer; that's needed for the next layer //printer = null; hatchedPolygons = null; borderPolygons = null; csgP = null; offBorder = null; offHatch = null; startNearHere = null; super.finalize(); } /** * @param printer * @param zValue * @param csgPol * @param ls * @param hatchDirection */ public LayerProducer(Printer printer, double zValue, RrCSGPolygonList csgPols, BranchGroup ls, RrHalfPlane hatchDirection, int layerNo, double zMax) throws Exception { layerNumber = layerNo; startNearHere = null; this.printer = printer; lowerShell = ls; csgP = csgPols; z = zValue; offBorder = csgPols.offset(printer.getExtruders(), true); offHatch = csgPols.offset(printer.getExtruders(), false); offBorder.divide(Preferences.tiny(), 1.01); offHatch.divide(Preferences.tiny(), 1.01); //RrGraphics g = new RrGraphics(offBorder, true); borderPolygons = offBorder.megList(); hatchedPolygons = new RrPolygonList(); hatchedPolygons.add(offHatch.hatch(hatchDirection, printer.getExtruders(), z, zMax)); // RrPolygonList pllist = new RrPolygonList(); // pllist.add(borderPolygons); // pllist.add(hatchedPolygons); // RrGraphics g = new RrGraphics(pllist, false); // RrBox big = csgPols.box().scale(1.1); // // double width = big.x().length(); // double height = big.y().length(); } /** * @return current X and Y position of the printer */ private Rr2Point posNow() { return new Rr2Point(printer.getX(), printer.getY()); } /** * speed up for short lines * @param p * @return * @throws ReprapException * @throws IOException */ private boolean shortLine(Rr2Point p) throws ReprapException, IOException { double shortLen = printer.getExtruder().getShortLength(); if(shortLen < 0) return false; Rr2Point a = Rr2Point.sub(posNow(), p); double amod = a.mod(); if(amod > shortLen) { Debug.d("Long segment. Current speed is: " + currentSpeed); return false; } printer.setSpeed(LinePrinter.speedFix(printer.getExtruder().getXYSpeed(), printer.getExtruder().getShortSpeed())); printer.printTo(p.x(), p.y(), z, true); printer.setSpeed(currentSpeed); Debug.d("Short segment at speed " + LinePrinter.speedFix(currentSpeed, printer.getExtruder().getShortSpeed()) +" derived from speed: " + currentSpeed); return true; } /** * @param first First point, the start of the line segment to be plotted. * @param second Second point, the end of the line segment to be plotted. * @param turnOff True if the extruder should be turned off at the end of this segment. * @throws ReprapException * @throws IOException */ private void plot(Rr2Point first, Rr2Point second, boolean turnOff) throws ReprapException, IOException { if (printer.isCancelled()) return; if(shortLine(first)) return; double speedUpLength = printer.getExtruder().getAngleSpeedUpLength(); if(speedUpLength > 0) { segmentSpeeds ss = new segmentSpeeds(posNow(), first, second, speedUpLength); if(ss.abandon) return; printer.printTo(ss.p1.x(), ss.p1.y(), z, false); if(ss.plotMiddle) { int straightSpeed = LinePrinter.speedFix(currentSpeed, (1 - printer.getExtruder().getAngleSpeedFactor())); printer.setSpeed(straightSpeed); printer.printTo(ss.p2.x(), ss.p2.y(), z, false); } printer.setSpeed(ss.speed(currentSpeed, printer.getExtruder().getAngleSpeedFactor())); printer.printTo(ss.p3.x(), ss.p3.y(), z, true); //pos = ss.p3; // Leave speed set for the start of the next line. } else printer.printTo(first.x(), first.y(), z, true); } /** * @param first * @param second * @param startUp * @param endUp * @throws ReprapException * @throws IOException */ private void move(Rr2Point first, Rr2Point second, boolean startUp, boolean endUp) throws ReprapException, IOException { if (printer.isCancelled()) return; if(startUp) { printer.setSpeed(printer.getFastSpeed()); printer.moveTo(first.x(), first.y(), z, startUp, endUp); return; } double speedUpLength = printer.getExtruder().getAngleSpeedUpLength(); if(speedUpLength > 0) { segmentSpeeds ss = new segmentSpeeds(posNow(), first, second, speedUpLength); if(ss.abandon) return; printer.moveTo(ss.p1.x(), ss.p1.y(), z, startUp, startUp); if(ss.plotMiddle) { printer.setSpeed(currentSpeed); printer.moveTo(ss.p2.x(), ss.p2.y(), z, startUp, startUp); } printer.setSpeed(ss.speed(currentSpeed, printer.getExtruder().getAngleSpeedFactor())); printer.moveTo(ss.p3.x(), ss.p3.y(), z, startUp, endUp); //pos = ss.p3; // Leave speed set for the start of the next movement. } else printer.moveTo(first.x(), first.y(), z, startUp, endUp); } /** * Plot a polygon * @throws IOException * @throws ReprapException * @return */ private void plot(RrPolygon p, boolean outline, boolean firstOneInLayer) throws ReprapException, IOException { int leng = p.size(); if(leng <= 1) { startNearHere = null; return; } // If the length of the plot is <0.05mm, don't bother with it. // This will not spot an attempt to plot 10,000 points in 1mm. double plotDist=0; Rr2Point lastPoint=p.point(0); for (int i=1; i<leng; i++) { Rr2Point n=p.point(i); plotDist+=Rr2Point.d(lastPoint, n); lastPoint=n; } if (plotDist<Preferences.machineResolution()*0.5) { Debug.d("Rejected line with "+leng+" points, length: "+plotDist); startNearHere = null; return; } Attributes att = p.getAttributes(); int baseSpeed = att.getExtruder(printer.getExtruders()).getXYSpeed(); int outlineSpeed = LinePrinter.speedFix(baseSpeed, att.getExtruder(printer.getExtruders()).getOutlineSpeed()); int infillSpeed = LinePrinter.speedFix(baseSpeed, att.getExtruder(printer.getExtruders()).getInfillSpeed()); printer.selectExtruder(att); // Warning: if incrementedStart is activated, this will override the randomStart if(outline && printer.getExtruder().incrementedStart()) p = p.incrementedStart(layerNumber); else if(outline && printer.getExtruder().randomStart()) p = p.randomStart(); // The last point is near where we want to start next if(outline) startNearHere = p.point(0); else startNearHere = p.point(p.size() - 1); int stopExtruding = leng + 10; int stopValve = stopExtruding; double extrudeBackLength = printer.getExtruder().getExtrusionOverRun(); double valveBackLength = printer.getExtruder().getValveOverRun(); if(extrudeBackLength >= valveBackLength) { if(extrudeBackLength > 0) stopExtruding = p.backStep(extrudeBackLength, outline); if(valveBackLength > 0) stopValve = p.backStep(valveBackLength, outline); } else { if(valveBackLength > 0) stopValve = p.backStep(valveBackLength, outline); if(extrudeBackLength > 0) stopExtruding = p.backStep(extrudeBackLength, outline); } if (printer.isCancelled()) return; printer.setSpeed(printer.getFastSpeed()); move(p.point(0), p.point(1), true, false); plot(p.point(0), p.point(1), false); // Print any lead-in. printer.printStartDelay(firstOneInLayer); if(outline) { printer.setSpeed(outlineSpeed); currentSpeed = outlineSpeed; } else { printer.setSpeed(infillSpeed); currentSpeed = infillSpeed; } if(outline) { for(int j = 1; j <= p.size(); j++) { int i = j%p.size(); Rr2Point next = p.point((j+1)%p.size()); if (printer.isCancelled()) { printer.stopExtruding(); move(posNow(), posNow(), true, true); return; } if(j > stopExtruding) { printer.stopExtruding(); move(p.point(i), next, false, false); } else plot(p.point(i), next, false); if(j > stopValve) { printer.stopValve(); move(p.point(i), next, false, false); } else plot(p.point(i), next, false); } } else { for(int i = 1; i < p.size(); i++) { Rr2Point next = p.point((i+1)%p.size()); if (printer.isCancelled()) { printer.stopExtruding(); move(posNow(), posNow(), true, true); return; } if(i > stopExtruding) { printer.stopExtruding(); move(p.point(i), next, false, false); } else plot(p.point(i), next, false); if(i > stopValve) { printer.stopValve(); move(p.point(i), next, false, false); } else plot(p.point(i), next, false); } } move(posNow(), posNow(), true, true); } private int plotOneMaterial(RrPolygonList polygons, int i, boolean outline, boolean firstOneInLayer) throws ReprapException, IOException { String material = polygons.polygon(i).getAttributes().getMaterial(); while(i < polygons.size() && polygons.polygon(i).getAttributes().getMaterial().equals(material)) { if (printer.isCancelled()) return i; plot(polygons.polygon(i), outline, firstOneInLayer); i++; } return i; } private boolean nextCommon(int ib, int ih) { commonBorder = ib; commonHatch = ih; if(borderPolygons.size() <= 0) { commonHatch = hatchedPolygons.size(); return false; } if(hatchedPolygons.size() <= 0) { commonBorder = borderPolygons.size(); return false; } for(int jb = ib; jb < borderPolygons.size(); jb++) { for(int jh = ih; jh < hatchedPolygons.size(); jh++) { if(borderPolygons.polygon(ib).getAttributes().getMaterial().equals( hatchedPolygons.polygon(ih).getAttributes().getMaterial())) { commonBorder = jb; commonHatch = jh; return true; } } } return false; } /** * Master plot function - draw everything * @throws IOException * @throws ReprapException */ public void plot() throws ReprapException, IOException { int ib, jb, ih, jh; boolean firstOneInLayer = true; //borderPolygons = borderPolygons.filterShorts(Preferences.machineResolution()*2); //hatchedPolygons = hatchedPolygons.filterShorts(Preferences.machineResolution()*2); ib = 0; ih = 0; while(nextCommon(ib, ih)) { for(jb = ib; jb < commonBorder; jb++) { if (printer.isCancelled()) break; plot(borderPolygons.polygon(jb), true, firstOneInLayer); firstOneInLayer = false; } ib = commonBorder; for(jh = ih; jh < commonHatch; jh++) { if (printer.isCancelled()) break; plot(hatchedPolygons.polygon(jh), false, firstOneInLayer); firstOneInLayer = false; } ih = commonHatch; firstOneInLayer = true; ib = plotOneMaterial(borderPolygons, ib, true, firstOneInLayer); firstOneInLayer = false; hatchedPolygons = hatchedPolygons.nearEnds(startNearHere); ih = plotOneMaterial(hatchedPolygons, ih, false, firstOneInLayer); } firstOneInLayer = true; for(jb = ib; jb < borderPolygons.size(); jb++) { if (printer.isCancelled()) break; plot(borderPolygons.polygon(jb), true, firstOneInLayer); } for(jh = ih; jh < commonHatch; jh++) { if (printer.isCancelled()) break; plot(hatchedPolygons.polygon(jh), false, firstOneInLayer); } printer.setLowerShell(lowerShell); } }