/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.openstreetmap.josm.plugins.importvec; import com.kitfox.svg.Group; import com.kitfox.svg.SVGDiagram; import com.kitfox.svg.SVGElement; import com.kitfox.svg.SVGUniverse; import com.kitfox.svg.ShapeElement; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.command.AddCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.coor.EastNorth; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.projection.Projection; import org.openstreetmap.josm.data.projection.Projections; import org.openstreetmap.josm.gui.PleaseWaitRunnable; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.tools.I18n; /** * * @author ak */ public class SvgImportTask extends PleaseWaitRunnable { LinkedList<Node> nodes = new LinkedList<>(); LinkedList<Way> ways = new LinkedList<>(); private List<File> files; private boolean canceled; public SvgImportTask(List<File> files) { super(I18n.tr("Importing..."), false); this.files = new ArrayList<>(files); } @Override protected void cancel() { this.canceled = true; } @Override protected void finish() { } Projection projection = Projections.getProjectionByCode("EPSG:3857"); // Mercator EastNorth center; double scale; Way currentway; double lastX; double lastY; private void appendNode(double x, double y) throws IOException { if (currentway == null) { throw new IOException("Shape is started incorectly"); } Node nd = new Node(projection.eastNorth2latlon(center.add(x * scale, -y * scale))); if (nd.getCoor().isOutSideWorld()) { throw new IOException("Shape goes outside the world"); } currentway.addNode(nd); nodes.add(nd); lastX = x; lastY = y; } private void appendNode(Point2D point) throws IOException { appendNode(point.getX(), point.getY()); } private static double sqr(double x) { return x * x; } private static double cube(double x) { return x * x * x; } private static Point2D interpolate_quad(double ax, double ay, double bx, double by, double cx, double cy, double t) { return new Point2D.Double(sqr(1 - t) * ax + 2 * (1 - t) * t * bx + t * t * cx, sqr(1 - t) * ay + 2 * (1 - t) * t * by + t * t * cy); } private static Point2D interpolate_cubic(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy, double t) { return new Point2D.Double(cube(1 - t) * ax + 3 * sqr(1 - t) * t * bx + 3 * (1 - t) * t * t * cx + t * t * t * dx, cube(1 - t) * ay + 3 * sqr(1 - t) * t * by + 3 * (1 - t) * t * t * cy + t * t * t * dy); } private void processElement(SVGElement el, AffineTransform transform) throws IOException { if (el instanceof Group) { AffineTransform oldTransform = transform; AffineTransform xform = ((Group) el).getXForm(); if (transform == null) { transform = xform; } else if (xform != null) { transform = new AffineTransform(transform); transform.concatenate(xform); } for (Object child : ((Group) el).getChildren(null)) { processElement((SVGElement) child, transform); } transform = oldTransform; } else if (el instanceof ShapeElement) { Shape shape = ((ShapeElement) el).getShape(); if (transform != null) { shape = transform.createTransformedShape(shape); } PathIterator it = shape.getPathIterator(null); while (!it.isDone()) { double[] coords = new double[6]; switch (it.currentSegment(coords)) { case PathIterator.SEG_MOVETO: currentway = new Way(); ways.add(currentway); appendNode(coords[0], coords[1]); break; case PathIterator.SEG_LINETO: appendNode(coords[0], coords[1]); break; case PathIterator.SEG_CLOSE: if (currentway.firstNode().getCoor().equalsEpsilon(nodes.getLast().getCoor())) { currentway.removeNode(nodes.removeLast()); } currentway.addNode(currentway.firstNode()); break; case PathIterator.SEG_QUADTO: double lastx = lastX; double lasty = lastY; for (int i = 1; i < Settings.getCurveSteps(); i++) { appendNode(interpolate_quad(lastx, lasty, coords[0], coords[1], coords[2], coords[3], i / Settings.getCurveSteps())); } appendNode(coords[2], coords[3]); break; case PathIterator.SEG_CUBICTO: lastx = lastX; lasty = lastY; for (int i = 1; i < Settings.getCurveSteps(); i++) { appendNode(interpolate_cubic(lastx, lasty, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], i / Settings.getCurveSteps())); } appendNode(coords[4], coords[5]); break; } it.next(); } } } @Override protected void realRun() throws IOException, OsmTransferException { LatLon center = Main.getProjection().eastNorth2latlon(Main.map.mapView.getCenter()); scale = Settings.getScaleNumerator() / Settings.getScaleDivisor() / Math.cos(Math.toRadians(center.lat())); this.center = projection.latlon2eastNorth(center); try { SVGUniverse universe = new SVGUniverse(); universe.setVerbose(Main.pref.getBoolean("importvec.verbose", false)); for (File f : files) { if (f.isDirectory()) continue; if (canceled) { return; } SVGDiagram diagram = universe.getDiagram(f.toURI()); ShapeElement root = diagram.getRoot(); if (root == null) { throw new IOException("Can't find root SVG element"); } Rectangle2D bbox = root.getBoundingBox(); this.center = this.center.add(-bbox.getCenterX() * scale, bbox.getCenterY() * scale); processElement(root, null); } } catch (IOException e) { throw e; } catch (Exception e) { throw new IOException(e); } LinkedList<Command> cmds = new LinkedList<>(); for (Node n : nodes) { cmds.add(new AddCommand(n)); } for (Way w : ways) { cmds.add(new AddCommand(w)); } Main.main.undoRedo.add(new SequenceCommand("Import primitives", cmds)); } }