/* 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.fx.machining; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.concurrent.Service; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; import javafx.scene.layout.VBox; import org.cirqwizard.generation.GenerationService; import org.cirqwizard.generation.ProcessingService; import org.cirqwizard.generation.optimizer.Chain; import org.cirqwizard.generation.optimizer.OptimizationService; import org.cirqwizard.generation.toolpath.*; import org.cirqwizard.logging.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; public abstract class LongProcessingMachining extends Machining { @FXML protected VBox generationPane; @FXML protected Label generationStageLabel; @FXML protected ProgressBar overallProgressBar; @FXML protected Label machiningTimeEstimationLabel; @FXML protected Button stopGenerationButton; private boolean generationCancelled; private ProcessingService boundService; private Service<Void> longProcessingService = new Service<Void>() { @Override protected Task<Void> createTask() { return new Task<Void>() { @Override protected Void call() throws Exception { try { List<Toolpath> toolpaths = new ArrayList<>(); cacheKey = getCacheKey(); GenerationService generationService = getGenerationService(); bindToService(generationService); List<Chain> chains = generationService.generate(); if (generationCancelled) { cacheKey = null; return null; } OptimizationService optimizationService = getOptimizationService(chains); bindToService(optimizationService); chains = optimizationService.optimize(); for (Chain p : chains) toolpaths.addAll(p.getSegments()); updateCache(toolpaths); getMainApplication().getContext().getPanel().setToolpaths(getCurrentLayer(), toolpaths); Platform.runLater(() -> pcbPane.toolpathsProperty().setValue( FXCollections.observableArrayList(toolpaths))); } catch (Throwable th) { LoggerFactory.getApplicationLogger().log(Level.WARNING, "Exception caught while generating tool paths", th); } return null; } }; } }; protected ToolpathsCacheKey cacheKey; protected abstract ToolpathsCacheKey getCacheKey(); protected abstract GenerationService getGenerationService(); protected abstract OptimizationService getOptimizationService(List<Chain> chains); protected abstract int getMergeTolerance(); protected abstract long getLayerModificationDate(); @Override public void refresh() { stopGenerationButton.setDisable(false); if (!isRunningDisabled()) goButton.disableProperty().bind(longProcessingService.runningProperty()); generationPane.visibleProperty().bind(longProcessingService.runningProperty()); veil.visibleProperty().bind(longProcessingService.runningProperty()); cacheKey = null; super.refresh(); } public boolean needsRestart() { return cacheKey == null || !cacheKey.equals(getCacheKey()); } private boolean loadFromCache() { try { String filename = getMainApplication().getContext().getPanelFile().getAbsolutePath(); filename = filename.substring(0, filename.lastIndexOf('.')); ToolpathsCache cache = ToolpathsPersistor.loadFromFile(filename + ".tmp"); if (!getMainApplication().getContext().getPanel().isCacheValid()) { File cacheFile = new File(filename + ".tmp"); if (cacheFile.exists()) cacheFile.delete(); return false; } if (cache == null) return false; List<Toolpath> toolpaths = cache.getToolpaths(getCacheKey()); if (toolpaths != null) { cacheKey = getCacheKey(); getMainApplication().getContext().getPanel().setToolpaths(getCurrentLayer(), toolpaths); pcbPane.toolpathsProperty().setValue(FXCollections.observableArrayList(toolpaths)); return true; } } catch (ToolpathPersistingException e) { LoggerFactory.getApplicationLogger().log(Level.INFO, e.getMessage(), e); } return false; } private void updateCache(List<Toolpath> toolpaths) { try { String filename = getMainApplication().getContext().getPanelFile().getAbsolutePath(); filename = filename.substring(0, filename.lastIndexOf('.')); ToolpathsCache cache = ToolpathsPersistor.loadFromFile(filename + ".tmp"); if (cache == null) cache = new ToolpathsCache(); cache.setToolpaths(getCacheKey(), toolpaths); getMainApplication().getContext().getPanel().updateCacheTimestamps(); getMainApplication().getContext().getPanel().save(getMainApplication().getContext().getPanelFile()); ToolpathsPersistor.saveToFile(cache, filename + ".tmp"); } catch (ToolpathPersistingException e) { LoggerFactory.getApplicationLogger().log(Level.INFO, e.getMessage(), e); } } protected void bindToService(ProcessingService service) { this.boundService = service; Platform.runLater(() -> { overallProgressBar.progressProperty().unbind(); generationStageLabel.textProperty().unbind(); machiningTimeEstimationLabel.textProperty().unbind(); overallProgressBar.progressProperty().bind(service.progressProperty()); generationStageLabel.textProperty().bind(service.currentStageProperty()); machiningTimeEstimationLabel.textProperty().bind(service.additionalInformationProperty()); }); } @Override protected void generateToolpaths() { if (!needsRestart()) return; stopGeneration(); if (loadFromCache()) return; veil.visibleProperty().bind(longProcessingService.runningProperty()); stopGenerationButton.setDisable(false); generationCancelled = false; longProcessingService.restart(); } @Override public void stopGeneration() { stopGenerationButton.setDisable(true); generationCancelled = true; if (boundService != null) boundService.setCancelled(true); } }