/*
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.optimizer;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.cirqwizard.geom.Arc;
import org.cirqwizard.geom.Point;
import org.cirqwizard.generation.toolpath.CircularToolpath;
import org.cirqwizard.generation.toolpath.CuttingToolpath;
import org.cirqwizard.generation.toolpath.LinearToolpath;
import org.cirqwizard.generation.toolpath.Toolpath;
import java.util.*;
public class ChainDetector
{
private static final int ROUNDING_FACTOR = 30;
private List<Toolpath> toolpaths;
private ArrayList<Point> vertices = new ArrayList<>();
private HashMap<Point, ArrayList<Toolpath>> map = new HashMap<>();
private DoubleProperty progressProperty = new SimpleDoubleProperty();
private StringProperty estimatedMachiningTimeProperty = new SimpleStringProperty();
public ChainDetector(List<Toolpath> toolpaths)
{
this.toolpaths = toolpaths;
generateMap();
}
public List<Chain> detect()
{
List<Chain> result = new ArrayList<>();
while (!vertices.isEmpty())
{
Point p = vertices.get(0);
if (map.get(p).isEmpty())
{
vertices.remove(0);
continue;
}
ArrayList<Toolpath> chainSegments = new ArrayList<>();
traverse(chainSegments, p, (CuttingToolpath) map.get(p).get(0));
result.add(new Chain(chainSegments));
}
return result;
}
public DoubleProperty progressProperty()
{
return progressProperty;
}
public StringProperty estimatedMachiningTimeProperty()
{
return estimatedMachiningTimeProperty;
}
private void traverse(ArrayList<Toolpath> result, Point point, CuttingToolpath edge)
{
if (edge.getCurve().getFrom().equals(point, ROUNDING_FACTOR))
result.add(edge);
else
{
if (edge instanceof LinearToolpath)
result.add(new LinearToolpath(edge.getToolDiameter(), edge.getCurve().getTo(), edge.getCurve().getFrom()));
else if (edge instanceof CircularToolpath)
{
Arc arc = (Arc) edge.getCurve();
result.add(new CircularToolpath(edge.getToolDiameter(), arc.getTo(), arc.getFrom(),
arc.getCenter(), arc.getRadius(), !arc.isClockwise()));
}
}
Point p = edge.getCurve().getFrom().round(ROUNDING_FACTOR);
if (p.equals(point, ROUNDING_FACTOR))
p = edge.getCurve().getTo().round(ROUNDING_FACTOR);
map.get(point).remove(edge);
if (map.get(p) != null)
{
map.get(p).remove(edge);
if (!map.get(p).isEmpty())
traverse(result, p, (CuttingToolpath) map.get(p).get(0));
}
}
private void generateMap()
{
for (Toolpath t : toolpaths)
{
Point from = ((CuttingToolpath)t).getCurve().getFrom().round(ROUNDING_FACTOR);
Point to = ((CuttingToolpath)t).getCurve().getTo().round(ROUNDING_FACTOR);
ArrayList<Toolpath> list = map.get(from);
if (list == null)
{
vertices.add(from);
list = new ArrayList<>();
map.put(from, list);
}
list.add(t);
list = map.get(to);
if (list == null)
{
vertices.add(to);
list = new ArrayList<>();
map.put(to, list);
}
list.add(t);
}
Collections.sort(vertices, new Comparator<Point>()
{
@Override
public int compare(Point o1, Point o2)
{
if (o1.getX() < o2.getX())
return -1;
if (o1.getX() > o2.getX())
return 1;
if (o1.getY() < o2.getY())
return -1;
return o1.getY() == o2.getY() ? 0 : 1;
}
});
}
}