package org.reprap.geometry;
import javax.swing.JCheckBoxMenuItem;
import org.reprap.Preferences;
import org.reprap.Printer;
import org.reprap.Extruder;
import org.reprap.Attributes;
import org.reprap.geometry.polygons.Point2D;
import org.reprap.geometry.polygons.Rectangle;
import org.reprap.geometry.polygons.PolygonList;
import org.reprap.geometry.polygons.Polygon;
import org.reprap.geometry.polygons.CSG2D;
import org.reprap.geometry.polygons.BooleanGrid;
import org.reprap.geometry.polyhedra.AllSTLsToBuild;
import org.reprap.gui.RepRapBuild;
import org.reprap.utilities.Debug;
import org.reprap.utilities.RrGraphics;
public class Producer {
private boolean paused = false;
//private LayerProducer layer = null;
protected LayerRules layerRules = null;
private RrGraphics simulationPlot = null;
/**
* The list of objects to be built
*/
protected RepRapBuild bld;
// protected boolean interLayerCooling;
//protected STLSlice stlc;
protected AllSTLsToBuild allSTLs;
/**
* @param preview
* @param builder
* @throws Exception
*/
public Producer(Printer pr, RepRapBuild builder) throws Exception
{
bld = builder;
allSTLs = bld.getSTLs();
layerRules = new LayerRules(pr, allSTLs, true);
if(Preferences.simulate())
{
simulationPlot = new RrGraphics("RepRap building simulation");
} else
simulationPlot = null;
}
/**
* Set the source checkbox used to determine if there should
* be a pause between segments.
*
* @param segmentPause The source checkbox used to determine
* if there should be a pause. This is a checkbox rather than
* a boolean so it can be changed on the fly.
*/
public void setSegmentPause(JCheckBoxMenuItem segmentPause) {
layerRules.getPrinter().setSegmentPause(segmentPause);
}
/**
* Set the source checkbox used to determine if there should
* be a pause between layers.
*
* @param layerPause The source checkbox used to determine
* if there should be a pause. This is a checkbox rather than
* a boolean so it can be changed on the fly.
*/
public void setLayerPause(JCheckBoxMenuItem layerPause) {
layerRules.getPrinter().setLayerPause(layerPause);
}
public void setCancelled(boolean c)
{
layerRules.getPrinter().setCancelled(c);
}
public void pause()
{
paused = true;
// if(layer != null)
// layer.pause();
}
public void resume()
{
paused = false;
// if(layer != null)
// layer.resume();
}
/**
* NB - this does not call wait - this is a purely interactive function and
* does not control the machine
*
*/
private void waitWhilePaused()
{
while(paused)
{
try
{
Thread.sleep(200);
} catch (Exception ex) {}
}
}
public int getLayers()
{
return layerRules.getMachineLayerMax();
}
public int getLayer()
{
return layerRules.getMachineLayer();
}
public void produce() throws Exception
{
// RrRectangle gp = layerRules.getBox();
// gp = new RrRectangle(new Rr2Point(gp.x().low() - 6, gp.y().low() - 6),
// new Rr2Point(gp.x().high() + 6, gp.y().high() + 6));
//layerRules.getPrinter().startRun(layerRules);
if(Preferences.Subtractive())
produceSubtractive();
else
{
if(layerRules.getTopDown())
produceAdditiveTopDown();
else
Debug.e("Producer.produce(): bottom-up builds no longer supported.");
//produceAdditiveGroundUp(gp);
}
}
private void fillFoundationRectangle(Printer reprap, Rectangle gp) throws Exception
{
PolygonList shield = new PolygonList();
Extruder e = reprap.getExtruder();
Attributes fa = new Attributes(e.getMaterial(), null, null, e.getAppearance());
// if(Preferences.loadGlobalBool("Shield")) // Should the foundation have a shield, or not?
// shield.add(allSTLs.shieldPolygon(fa));
CSG2D rect = CSG2D.RrCSGFromBox(gp);
BooleanGrid bg = new BooleanGrid(rect, gp.scale(1.1), fa);
PolygonList h[] = {shield, bg.hatch(layerRules.getHatchDirection(e, false), layerRules.getHatchWidth(e), bg.attribute())};
LayerProducer lp = new LayerProducer(h, layerRules, simulationPlot);
lp.plot();
reprap.getExtruder().stopExtruding();
//reprap.setFeedrate(reprap.getFastFeedrateXY());
}
// private void layFoundationGroundUp(RrRectangle gp) throws Exception
// {
// if(layerRules.getFoundationLayers() <= 0)
// return;
//
// Printer reprap = layerRules.getPrinter();
//
// while(layerRules.getMachineLayer() < layerRules.getFoundationLayers())
// {
//
// if (reprap.isCancelled())
// break;
// waitWhilePaused();
//
// Debug.d("Commencing foundation layer at " + layerRules.getMachineZ());
//
// reprap.startingLayer(layerRules);
// // Change Z height
// //reprap.singleMove(reprap.getX(), reprap.getY(), layerRules.getMachineZ(), reprap.getFastFeedrateZ());
// fillFoundationRectangle(reprap, gp);
// reprap.finishedLayer(layerRules);
// reprap.betweenLayers(layerRules);
// layerRules.stepMachine(reprap.getExtruder());
// }
// layerRules.setLayingSupport(false);
// }
private void layFoundationTopDown(Rectangle gp) throws Exception
{
if(layerRules.getFoundationLayers() <= 0)
return;
layerRules.setLayingSupport(true);
layerRules.getPrinter().setSeparating(false);
Printer reprap = layerRules.getPrinter();
while(layerRules.getMachineLayer() >= 0)
{
if (reprap.isCancelled())
break;
waitWhilePaused();
Debug.d("Commencing foundation layer at " + layerRules.getMachineZ());
reprap.startingLayer(layerRules);
// Change Z height
//reprap.singleMove(reprap.getX(), reprap.getY(), layerRules.getMachineZ(), reprap.getFastFeedrateZ());
fillFoundationRectangle(reprap, gp);
reprap.finishedLayer(layerRules);
reprap.betweenLayers(layerRules);
layerRules.stepMachine();
}
}
/**
* @throws Exception
*/
private void produceAdditiveTopDown() throws Exception
{
bld.mouseToWorld();
Printer reprap = layerRules.getPrinter();
layerRules.setLayingSupport(false);
//BooleanGridList slice, previousSlice;
int lastExtruder = -1;
int totalPhysicalExtruders = 0;
for(int extruder = 0; extruder < reprap.getExtruders().length; extruder++)
{
int thisExtruder = reprap.getExtruders()[extruder].getPhysicalExtruderNumber();
if(thisExtruder > lastExtruder)
{
totalPhysicalExtruders++;
if(thisExtruder - lastExtruder != 1)
{
Debug.e("Producer.produceAdditiveTopDown(): Physical extruders out of sequence: " +
lastExtruder + " then " + thisExtruder);
Debug.e("(Extruder addresses should be monotonically increasing starting at 0.)");
}
lastExtruder = thisExtruder;
}
}
PolygonList allPolygons[] = new PolygonList[totalPhysicalExtruders];
PolygonList tempBorderPolygons[] = new PolygonList[totalPhysicalExtruders];
PolygonList tempFillPolygons[] = new PolygonList[totalPhysicalExtruders];
boolean firstTimeRound = true;
while(layerRules.getModelLayer() > 0 )
{
if(layerRules.getModelLayer() == 0)
reprap.setSeparating(true);
else
reprap.setSeparating(false);
if (reprap.isCancelled())
break;
waitWhilePaused();
Debug.d("Commencing model layer " + layerRules.getModelLayer() + " at " + layerRules.getMachineZ());
reprap.startingLayer(layerRules);
reprap.waitWhileBufferNotEmpty();
reprap.slowBuffer();
for(int physicalExtruder = 0; physicalExtruder < allPolygons.length; physicalExtruder++)
allPolygons[physicalExtruder] = new PolygonList();
boolean shield = true;
Point2D startNearHere = new Point2D(0, 0);
for(int stl = 0; stl < allSTLs.size(); stl++)
{
PolygonList fills = allSTLs.computeInfill(stl);
PolygonList borders = allSTLs.computeOutlines(stl, fills, shield);
fills = fills.cullShorts();
shield = false;
PolygonList support = allSTLs.computeSupport(stl);
for(int physicalExtruder = 0; physicalExtruder < allPolygons.length; physicalExtruder++)
{
tempBorderPolygons[physicalExtruder] = new PolygonList();
tempFillPolygons[physicalExtruder] = new PolygonList();
}
for(int pol = 0; pol < borders.size(); pol++)
{
Polygon p = borders.polygon(pol);
tempBorderPolygons[p.getAttributes().getExtruder().getPhysicalExtruderNumber()].add(p);
}
for(int pol = 0; pol < fills.size(); pol++)
{
Polygon p = fills.polygon(pol);
tempFillPolygons[p.getAttributes().getExtruder().getPhysicalExtruderNumber()].add(p);
}
for(int pol = 0; pol < support.size(); pol++)
{
Polygon p = support.polygon(pol);
tempFillPolygons[p.getAttributes().getExtruder().getPhysicalExtruderNumber()].add(p);
}
for(int physicalExtruder = 0; physicalExtruder < allPolygons.length; physicalExtruder++)
{
if(tempBorderPolygons[physicalExtruder].size() > 0)
{
double linkUp = tempBorderPolygons[physicalExtruder].polygon(0).getAttributes().getExtruder().getExtrusionSize();
linkUp = (4*linkUp*linkUp);
tempBorderPolygons[physicalExtruder].radicalReOrder(linkUp);
tempBorderPolygons[physicalExtruder] = tempBorderPolygons[physicalExtruder].nearEnds(startNearHere, false, -1);
if(tempBorderPolygons[physicalExtruder].size() > 0)
{
Polygon last = tempBorderPolygons[physicalExtruder].polygon(tempBorderPolygons[physicalExtruder].size() - 1);
startNearHere = last.point(last.size() - 1);
}
allPolygons[physicalExtruder].add(tempBorderPolygons[physicalExtruder]);
}
if(tempFillPolygons[physicalExtruder].size() > 0)
{
double linkUp = tempFillPolygons[physicalExtruder].polygon(0).getAttributes().getExtruder().getExtrusionSize();
linkUp = (4*linkUp*linkUp);
tempFillPolygons[physicalExtruder].radicalReOrder(linkUp);
tempFillPolygons[physicalExtruder] = tempFillPolygons[physicalExtruder].nearEnds(startNearHere, false, -1);
if(tempFillPolygons[physicalExtruder].size() > 0)
{
Polygon last = tempFillPolygons[physicalExtruder].polygon(tempFillPolygons[physicalExtruder].size() - 1);
startNearHere = last.point(last.size() - 1);
}
allPolygons[physicalExtruder].add(tempFillPolygons[physicalExtruder]);
}
}
}
layerRules.setFirstAndLast(allPolygons);
LayerProducer lp = new LayerProducer(allPolygons, layerRules, simulationPlot);
lp.plot();
reprap.finishedLayer(layerRules);
reprap.betweenLayers(layerRules);
if(firstTimeRound)
{
reprap.setTop(reprap.getX(), reprap.getY(), reprap.getZ());
firstTimeRound = false;
}
allSTLs.destroyLayer();
layerRules.step();
}
layFoundationTopDown(layerRules.getBox());
layerRules.reverseLayers();
}
private void produceSubtractive() throws Exception
{
Debug.e("Need to implement the Producer.produceSubtractive() function... :-)");
}
/**
* The total distance moved is the total distance extruded plus
* plus additional movements of the extruder when no materials
* was deposited
*
* @return total distance the extruder has moved
*/
public double getTotalDistanceMoved() {
return layerRules.getPrinter().getTotalDistanceMoved();
}
/**
* @return total distance that has been extruded in millimeters
*/
public double getTotalDistanceExtruded() {
return layerRules.getPrinter().getTotalDistanceExtruded();
}
/**
* TODO: This figure needs to get added up as we go along to allow for different extruders
* @return total volume that has been extruded
*/
public double getTotalVolumeExtruded() {
return layerRules.getPrinter().getTotalDistanceExtruded() * layerRules.getPrinter().getExtruder().getExtrusionHeight() *
layerRules.getPrinter().getExtruder().getExtrusionSize();
}
/**
*
*/
public void dispose() {
layerRules.getPrinter().dispose();
}
/**
* @return total elapsed time in seconds between start and end of building the 3D object
*/
public double getTotalElapsedTime() {
return layerRules.getPrinter().getTotalElapsedTime();
}
}