/*
* 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 org.reprap.Printer;
import org.reprap.Attributes;
import org.reprap.Preferences;
//import org.reprap.ReprapException;
//import org.reprap.devices.pseudo.LinePrinter;
import org.reprap.geometry.polygons.Point2D;
//import org.reprap.geometry.polygons.RrCSGPolygonList;
import org.reprap.geometry.polygons.Polygon;
import org.reprap.geometry.polygons.PolygonAttributes;
import org.reprap.geometry.polygons.PolygonList;
import org.reprap.geometry.polygons.Rectangle;
import org.reprap.utilities.Debug;
import org.reprap.utilities.RrGraphics;
/**
*
*/
class segmentSpeeds
{
/**
*
*/
public Point2D p1, p2, p3;
/**
*
*/
public double ca;
/**
*
*/
public boolean plotMiddle;
/**
*
*/
public boolean abandon;
/**
* @param before
* @param now
* @param after
* @param fastLength
*/
public segmentSpeeds(Point2D before, Point2D now, Point2D after, double fastLength)
{
Point2D a = Point2D.sub(now, before);
double amod = a.mod();
abandon = amod == 0;
if(abandon)
return;
Point2D b = Point2D.sub(after, now);
if(b.mod() == 0)
ca = 0;
else
ca = Point2D.mul(a.norm(), b.norm());
plotMiddle = true;
if(amod <= 2*fastLength)
{
fastLength = amod*0.5;
plotMiddle = false;
}
a = a.norm();
p1 = Point2D.add(before, Point2D.mul(a, fastLength));
p2 = Point2D.add(p1, Point2D.mul(a, amod - 2*fastLength));
p3 = Point2D.add(p2, Point2D.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 {
private RrGraphics simulationPlot = null;
/**
*
*/
private LayerRules layerConditions = null;
/**
*
*/
private boolean paused = false;
private PolygonList allPolygons[];
/**
* The clue is in the name...
*/
private double currentFeedrate;
/**
* Record the end of each polygon as a clue where to start next
*/
private Point2D 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;
if(startNearHere != null)
startNearHere.destroy();
startNearHere = null;
allPolygons = null;
beingDestroyed = false;
}
/**
* Set up a normal layer
* @param boolGrdSliceols
* @param ls
* @param lc
* @param simPlot
* @throws Exception
*/
public LayerProducer(PolygonList ap[], LayerRules lc, RrGraphics simPlot) throws Exception
{
layerConditions = lc;
startNearHere = null;
simulationPlot = simPlot;
allPolygons = ap;
if(simulationPlot != null)
{
if(!simulationPlot.isInitialised())
{
Rectangle rec = lc.getBox();
if(Preferences.loadGlobalBool("Shield"))
rec.expand(Point2D.add(rec.sw(), new Point2D(-7, -7))); // TODO: Yuk - this should be a parameter
simulationPlot.init(rec, false, "" + lc.getModelLayer() + " (z=" + lc.getModelZ() + ")");
} else
simulationPlot.cleanPolygons("" + lc.getModelLayer() + " (z=" + lc.getModelZ() + ")");
}
}
/**
* Stop printing
*
*/
public void pause()
{
paused = true;
}
/**
* Start printing
*
*/
public void resume()
{
paused = false;
}
/**
* @return current X and Y position of the printer
*/
private Point2D posNow()
{
return new Point2D(layerConditions.getPrinter().getX(), layerConditions.getPrinter().getY());
}
/**
* speed up for short lines
* @param p
* @return
* @throws Exception
*/
private boolean shortLine(Point2D p, boolean stopExtruder, boolean closeValve) throws Exception
{
Printer printer = layerConditions.getPrinter();
double shortLen = printer.getExtruder().getShortLength();
if(shortLen < 0)
return false;
Point2D a = Point2D.sub(posNow(), p);
double amod = a.mod();
if(amod > shortLen) {
// Debug.d("Long segment. Current feedrate is: " + currentFeedrate);
return false;
}
//printer.setFeedrate(printer.getExtruder().getShortLineFeedrate());
// TODO: FIX THIS
// printer.setSpeed(LinePrinter.speedFix(printer.getExtruder().getXYSpeed(),
// printer.getExtruder().getShortSpeed()));
printer.printTo(p.x(), p.y(), layerConditions.getMachineZ(), printer.getExtruder().getShortLineFeedrate(), stopExtruder, closeValve);
//printer.setFeedrate(currentFeedrate);
return true;
}
/**
* @param first First point, the end of the line segment to be plotted to from the current position.
* @param second Second point, the end of the next line segment; used for angle calculations
* @param turnOff True if the extruder should be turned off at the end of this segment.
* @throws Exception
*/
private void plot(Point2D first, Point2D second, boolean stopExtruder, boolean closeValve) throws Exception
{
Printer printer = layerConditions.getPrinter();
if (printer.isCancelled()) return;
// Don't call delay; this isn't controlling the printer
while(paused)
{
try
{
Thread.sleep(200);
} catch (Exception ex) {}
}
if(shortLine(first, stopExtruder, closeValve))
return;
double z = layerConditions.getMachineZ();
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, currentFeedrate, false, false);
if(ss.plotMiddle)
{
//TODO: FIX THIS.
// int straightSpeed = LinePrinter.speedFix(currentSpeed, (1 -
// printer.getExtruder().getAngleSpeedFactor()));
//printer.setFeedrate(printer.getExtruder().getAngleFeedrate());
printer.printTo(ss.p2.x(), ss.p2.y(), z, printer.getExtruder().getAngleFeedrate(), false, false);
}
//printer.setSpeed(ss.speed(currentSpeed, printer.getExtruder().getAngleSpeedFactor()));
//printer.setFeedrate(printer.getExtruder().getAngleFeedrate());
printer.printTo(ss.p3.x(), ss.p3.y(), z, printer.getExtruder().getAngleFeedrate(), stopExtruder, closeValve);
//pos = ss.p3;
// Leave speed set for the start of the next line.
} else
printer.printTo(first.x(), first.y(), z, currentFeedrate, stopExtruder, closeValve);
}
private void singleMove(Point2D p)
{
Printer pt = layerConditions.getPrinter();
pt.singleMove(p.x(), p.y(), pt.getZ(), pt.getFastXYFeedrate(), true);
}
/**
* @param first
* @param second
* @param startUp
* @param endUp
* @throws Exception
*/
private void move(Point2D first, Point2D second, boolean startUp, boolean endUp, boolean fast)
throws Exception
{
Printer printer = layerConditions.getPrinter();
if (printer.isCancelled()) return;
// Don't call delay; this isn't controlling the printer
while(paused)
{
try
{
Thread.sleep(200);
} catch (Exception ex) {}
}
double z = layerConditions.getMachineZ();
//if(startUp)
if(fast)
{
//printer.setFeedrate(printer.getFastFeedrateXY());
printer.moveTo(first.x(), first.y(), z, printer.getExtruder().getFastXYFeedrate(), 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, printer.getCurrentFeedrate(), startUp, startUp);
if(ss.plotMiddle)
{
//printer.setFeedrate(currentFeedrate);
printer.moveTo(ss.p2.x(), ss.p2.y(), z, currentFeedrate, startUp, startUp);
}
//TODO: FIX ME!
//printer.setSpeed(ss.speed(currentSpeed, printer.getExtruder().getAngleSpeedFactor()));
//printer.setFeedrate(printer.getExtruder().getAngleFeedrate());
printer.moveTo(ss.p3.x(), ss.p3.y(), z, printer.getExtruder().getAngleFeedrate(), startUp, endUp);
//pos = ss.p3;
// Leave speed set for the start of the next movement.
} else
printer.moveTo(first.x(), first.y(), z, currentFeedrate, startUp, endUp);
}
/**
* Plot a polygon
* @return
* @throws Exception
*/
private void plot(Polygon p, boolean firstOneInLayer) throws Exception
{
Attributes att = p.getAttributes();
PolygonAttributes pAtt = p.getPolygonAttribute();
Printer printer = layerConditions.getPrinter();
double outlineFeedrate = att.getExtruder().getOutlineFeedrate();
double infillFeedrate = att.getExtruder().getInfillFeedrate();
boolean acc = att.getExtruder().getMaxAcceleration() > 0;
if(p.size() <= 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;
Point2D lastPoint=p.point(0);
for (int i=1; i<p.size(); i++)
{
Point2D n=p.point(i);
plotDist+=Point2D.d(lastPoint, n);
lastPoint=n;
}
if (plotDist<Preferences.machineResolution()*0.5) {
Debug.d("Rejected line with "+p.size()+" points, length: "+plotDist);
//startNearHere = null;
return;
}
double currentZ = printer.getZ();
if(firstOneInLayer)
{
// The next line tells the printer that it is already at the first point. It is not, but code will be added just before this
// to put it there by the LayerRules function that reverses the top-down order of the layers.
if(Preferences.loadGlobalBool("RepRapAccelerations"))
printer.singleMove(p.point(0).x(), p.point(0).y(), currentZ, printer.getSlowXYFeedrate(), false);
else
printer.singleMove(p.point(0).x(), p.point(0).y(), currentZ, printer.getFastXYFeedrate(), false);
printer.forceNextExtruder();
}
printer.selectExtruder(att);
if (printer.isCancelled()) return;
// If getMinLiftedZ() is negative, never lift the head
double liftZ = att.getExtruder().getLift();
Boolean lift = att.getExtruder().getMinLiftedZ() >= 0 || liftZ > 0;
if(acc)
{
if(Preferences.loadGlobalBool("RepRapAccelerations"))
p.setSpeeds(printer.getFastXYFeedrate(), att.getExtruder().getSlowXYFeedrate(), p.isClosed()?outlineFeedrate:infillFeedrate,
att.getExtruder().getMaxAcceleration());
else
p.setSpeeds(printer.getFastXYFeedrate(), att.getExtruder().getFastXYFeedrate(), p.isClosed()?outlineFeedrate:infillFeedrate,
att.getExtruder().getMaxAcceleration());
}
double extrudeBackLength = att.getExtruder().getExtrusionOverRun();
double valveBackLength = att.getExtruder().getValveOverRun();
if(extrudeBackLength > 0 && valveBackLength > 0)
Debug.e("LayerProducer.plot(): extruder has both valve backoff and extrude backoff specified.");
p.backStepExtrude(extrudeBackLength);
p.backStepValve(valveBackLength);
if(liftZ > 0)
printer.singleMove(printer.getX(), printer.getY(), currentZ + liftZ, printer.getFastFeedrateZ(), true);
currentFeedrate = att.getExtruder().getFastXYFeedrate();
singleMove(p.point(0));
if(liftZ > 0)
printer.singleMove(printer.getX(), printer.getY(), currentZ, printer.getFastFeedrateZ(), true);
if(acc | (!Preferences.loadGlobalBool("RepRapAccelerations")))
currentFeedrate = p.speed(0);
else
{
if(p.isClosed())
{
currentFeedrate = outlineFeedrate;
} else
{
currentFeedrate = infillFeedrate;
}
}
plot(p.point(0), p.point(1), false, false);
// Print any lead-in.
printer.printStartDelay(firstOneInLayer);
boolean extrudeOff = false;
boolean valveOff = false;
boolean oldexoff;
double oldFeedFactor = att.getExtruder().getExtrudeRatio();
if(pAtt != null)
att.getExtruder().setExtrudeRatio(oldFeedFactor*pAtt.getBridgeThin());
for(int i = 1; i < p.size(); i++)
{
Point2D next = p.point((i+1)%p.size());
if (printer.isCancelled())
{
printer.stopMotor();
singleMove(posNow());
move(posNow(), posNow(), lift, lift, true);
return;
}
if(acc)
currentFeedrate = p.speed(i);
oldexoff = extrudeOff;
extrudeOff = (i > p.extrudeEnd() && extrudeBackLength > 0) || i == p.size()-1;
valveOff = (i > p.valveEnd() && valveBackLength > 0) || i == p.size()-1;
plot(p.point(i), next, extrudeOff, valveOff);
if(oldexoff ^ extrudeOff)
printer.printEndReverse();
}
// Restore sanity
att.getExtruder().setExtrudeRatio(oldFeedFactor);
if(p.isClosed())
move(p.point(0), p.point(0), false, false, true);
move(posNow(), posNow(), lift, lift, true);
// The last point is near where we want to start next
if(p.isClosed())
startNearHere = p.point(0);
else
startNearHere = p.point(p.size() - 1);
if(simulationPlot != null)
{
PolygonList pgl = new PolygonList();
pgl.add(p);
simulationPlot.add(pgl);
}
}
/**
* Master plot function - draw everything. Supress border and/or hatch by
* setting borderPolygons and/or hatchedPolygons null
* @throws Exception
*/
public void plot() throws Exception
{
boolean firstOneInLayer = true;
for(int i = 0; i < allPolygons.length; i++)
{
firstOneInLayer = true;
PolygonList pl = allPolygons[i];
for(int j = 0; j < pl.size(); j++)
{
plot(pl.polygon(j), firstOneInLayer);
firstOneInLayer = false;
}
}
}
}