// License: GPL. For details, see LICENSE file. package pdfimport.pdfbox; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.openstreetmap.josm.gui.progress.ProgressMonitor; import pdfimport.LayerInfo; import pdfimport.PathOptimizer; import pdfimport.PdfPath; public class GraphicsProcessor { public PathOptimizer target; private Shape clipShape; private List<PdfPath> clipPath; private final LayerInfo info = new LayerInfo(); int pathNo = 0; private boolean complexClipShape; private boolean clipAreaDrawn; private final AffineTransform transform; private final ProgressMonitor monitor; private final int maxPaths; public GraphicsProcessor(PathOptimizer target, int rotation, int maxPaths, ProgressMonitor monitor) { this.maxPaths = maxPaths; this.target = target; this.transform = new AffineTransform(); this.transform.rotate(-Math.toRadians(rotation)); this.info.stroke = Color.BLACK; this.info.fill = Color.BLACK; this.monitor = monitor; } private void addPath(Shape s, boolean closed) { pathNo++; if (pathNo % 100 == 0) { this.monitor.setCustomText(tr(" {0} objects so far", pathNo)); } if (pathNo >= maxPaths) { return; } List<PdfPath> paths = this.parsePath(s, closed); for (PdfPath p: paths) { p.nr = pathNo; } if (paths.size() > 1) { this.target.addMultiPath(this.info, paths); this.parsePath(s, closed); } else if (paths.size() == 1) { this.target.addPath(this.info, paths.get(0)); } } private List<PdfPath> parsePath(Shape s, boolean closed) { List<PdfPath> result = new ArrayList<>(2); List<Point2D> points = new ArrayList<>(2); PathIterator iter = s.getPathIterator(null); double[] coords = new double[6]; while (!iter.isDone()) { int type = iter.currentSegment(coords); if (type == PathIterator.SEG_CLOSE) { //close polygon this.addPoint(points, points.get(0)); if (points.size() > 1) { result.add(new PdfPath(points)); } points = new ArrayList<>(2); } else if (type == PathIterator.SEG_CUBICTO) { //cubic curve this.addPoint(points, this.parsePoint(coords, 4)); } else if (type == PathIterator.SEG_LINETO) { this.addPoint(points, this.parsePoint(coords, 0)); } else if (type == PathIterator.SEG_MOVETO) { //new path if (points.size() > 1) { result.add(new PdfPath(points)); } points = new ArrayList<>(2); this.addPoint(points, this.parsePoint(coords, 0)); } else if (type == PathIterator.SEG_QUADTO) { //quadratic curve this.addPoint(points, this.parsePoint(coords, 2)); } else if (type == PathIterator.WIND_EVEN_ODD) { //fill even odd } else if (type == PathIterator.WIND_NON_ZERO) { //fill all } iter.next(); } if (points.size() > 1) { if (closed) { this.addPoint(points, points.get(0)); } result.add(new PdfPath(points)); } return result; } private void addPoint(List<Point2D> points, Point2D point) { if (points.size() > 0) { Point2D prevPoint = points.get(points.size() - 1); if (prevPoint.getX() == point.getX() && prevPoint.getY() == point.getY()) { return; } } points.add(point); } private Point2D parsePoint(double[] buffer, int offset) { //invert Y. Point2D point = new Point2D.Double(buffer[offset], buffer[offset + 1]); Point2D dest = new Point2D.Double(); this.transform.transform(point, dest); return this.target.getUniquePoint(dest); } public void drawPath(Shape path, Color stroke, Color fill, int windingRule) { if (complexClipShape) { if (!this.clipAreaDrawn) { this.info.stroke = null; this.info.fill = Color.CYAN; this.addPath(this.clipShape, true); this.clipAreaDrawn = true; } } if (!complexClipShape || fill != null) { this.info.stroke = stroke; this.info.fill = fill; this.addPath(path, fill != null); } } public void drawImage() { if (!this.clipAreaDrawn) { this.info.stroke = null; this.info.fill = Color.CYAN; this.addPath(this.clipShape, true); this.clipAreaDrawn = true; } } public void setClip(Shape clip) { if (this.shapesEqual(this.clipShape, clip)) return; this.clipPath = this.parsePath(clip, true); boolean complexClipPath = false; if (clipPath.size() > 1) { complexClipPath = true; } else if (clipPath.size() == 1 && clipPath.get(0).points.size() > 5) { //more than 4 points. complexClipPath = true; } this.complexClipShape = complexClipPath; this.clipAreaDrawn = false; this.clipShape = clip; } private boolean shapesEqual(Shape shape1, Shape shape2) { if (shape1 == null || shape2 == null) { return false; } return shape1.getBounds2D().equals(shape2.getBounds2D()); } public void setStroke(Stroke s) { BasicStroke stroke = (BasicStroke) s; this.info.width = stroke.getLineWidth(); this.info.dash = 0; if (stroke.getDashArray() != null) { this.info.dash = Arrays.hashCode(stroke.getDashArray()); } } public void drawString(float x, float y, String character, Color color) { // TODO Auto-generated method stub } }