/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.cirqwizard.generation;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import org.cirqwizard.geom.Point;
import org.cirqwizard.gerber.GerberPrimitive;
import org.cirqwizard.logging.LoggerFactory;
import org.cirqwizard.generation.toolpath.Toolpath;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class RubOutToolpathGenerator extends AbstractToolpathGenerator
{
private final static int WINDOW_SIZE = 5000;
private final static int WINDOWS_HORIZONTAL_OVERLAP = 5;
private final static int WINDOWS_VERTICAL_OVERLAP = 500;
private final static int OOM_RETRY_DELAY = 1000;
private int width;
private int height;
private int toolDiameter;
private int overlap;
private int threadCount;
private double scale = 1; // It has to go
private BooleanProperty cancelledProperty;
public void init(int width, int height, int inflation, int toolDiameter, int overlap, List<GerberPrimitive> primitives, int threadCount,
BooleanProperty cancelledProperty)
{
this.width = width;
this.height = height;
this.inflation = inflation;
this.toolDiameter = toolDiameter;
this.overlap = overlap;
this.primitives = primitives;
this.threadCount = threadCount;
this.cancelledProperty = cancelledProperty;
}
public List<Toolpath> generate()
{
final Vector<Toolpath> segments = new Vector<>();
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
for (int x = 0; x < width; x += WINDOW_SIZE)
for (int y = 0; y < height; y += WINDOW_SIZE)
pool.submit(new WindowGeneratorThread(x > WINDOWS_HORIZONTAL_OVERLAP ? x - WINDOWS_HORIZONTAL_OVERLAP : x, y > WINDOWS_VERTICAL_OVERLAP ? y - WINDOWS_VERTICAL_OVERLAP : y, segments));
try
{
pool.shutdown();
pool.awaitTermination(10, TimeUnit.DAYS);
}
catch (InterruptedException e)
{
}
return segments;
}
private class WindowGeneratorThread implements Runnable
{
private int x;
private int y;
private Vector<Toolpath> segments;
private WindowGeneratorThread(int x, int y, Vector<Toolpath> segments)
{
this.x = x;
this.y = y;
this.segments = segments;
}
@Override
public void run()
{
if (cancelledProperty.get())
return;
try
{
Platform.runLater(() -> progressProperty.set(((double) y * WINDOW_SIZE + (double) x * height) / ((double) width * height)));
Point offset = new Point(x, y);
int windowWidth = Math.min(WINDOW_SIZE + 2 * WINDOWS_HORIZONTAL_OVERLAP, width - x);
int windowHeight = Math.min(WINDOW_SIZE + 2 * WINDOWS_VERTICAL_OVERLAP, height - y);
RasterWindow window = new RasterWindow(new Point(x, y), windowWidth, windowHeight, scale);
window.render(primitives, inflation + toolDiameter / 2);
RubOutGenerator g = new RubOutGenerator(window.getBufferedImage(), toolDiameter, overlap);
window = null;
segments.addAll(translateToolpaths(g.process(), offset, scale));
}
catch (OutOfMemoryError e)
{
LoggerFactory.getApplicationLogger().log(Level.WARNING, "Out of memory caught while generating tool paths. Retrying", e);
try
{
Thread.sleep((int)((1.0 + Math.random()) * OOM_RETRY_DELAY));
}
catch (InterruptedException e1) {}
run();
}
catch (Throwable e)
{
LoggerFactory.logException("Error while generating tool paths", e);
}
}
}
}