package org.openstreetmap.josm.plugins.routes.paint; import java.awt.Graphics2D; import java.awt.Point; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.List; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.NavigatableComponent; public abstract class AbstractLinePainter implements PathPainter { // Following two method copied from http://blog.persistent.info/2004/03/java-lineline-intersections.html protected boolean getLineLineIntersection(Line2D.Double l1, Line2D.Double l2, Point intersection) { double x1 = l1.getX1(), y1 = l1.getY1(), x2 = l1.getX2(), y2 = l1.getY2(), x3 = l2.getX1(), y3 = l2.getY1(), x4 = l2.getX2(), y4 = l2.getY2(); double dx1 = x2 - x1; double dx2 = x4 - x3; double dy1 = y2 - y1; double dy2 = y4 - y3; double ua = (dx2 * (y1 - y3) - dy2 * (x1 - x3)) / (dy2 * dx1 - dx2 * dy1); if (Math.abs(dy2 * dx1 - dx2 * dy1) < 0.0001) { intersection.x = (int)l1.x2; intersection.y = (int)l1.y2; return false; } else { intersection.x = (int)(x1 + ua * (x2 - x1)); intersection.y = (int)(y1 + ua * (y2 - y1)); } return true; } protected double det(double a, double b, double c, double d) { return a * d - b * c; } protected Point shiftPoint(Point2D p1, Point2D p2, double shift) { double dx = p2.getX() - p1.getX(); double dy = p2.getY() - p1.getY(); // Perpendicular vector double ndx = -dy; double ndy = dx; // Normalize double length = Math.sqrt(ndx * ndx + ndy * ndy); ndx = ndx / length; ndy = ndy / length; return new Point((int)(p1.getX() + shift * ndx), (int)(p1.getY() + shift * ndy)); } protected Line2D.Double shiftLine(Point2D p1, Point2D p2, double shift) { double dx = p2.getX() - p1.getX(); double dy = p2.getY() - p1.getY(); Point2D point1 = shiftPoint(p1, p2, shift); Point2D point2 = new Point2D.Double(point1.getX() + dx, point1.getY() + dy); return new Line2D.Double( point1, point2); } protected GeneralPath getPath(Graphics2D g, MapView mapView, List<Node> nodes, double shift) { GeneralPath path = new GeneralPath(); if (nodes.size() < 2) { return path; } Point p1 = null; Point p2 = null; Point p3 = null; Point lastPoint = null; for (Node n: nodes) { Point p = mapView.getPoint(n); if (!p.equals(p3)) { p1 = p2; p2 = p3; p3 = p; } else { continue; } p = null; if (p2 != null) { if (p1 == null) { p = shiftPoint(p2, p3, shift); } else { Line2D.Double line1 = shiftLine(p1, p2, shift); Line2D.Double line2 = shiftLine(p2, p3, shift); /*path.moveTo((float)line1.x1, (float)line1.y1); path.lineTo((float)line1.x2, (float)line1.y2); path.moveTo((float)line2.x1, (float)line2.y1); path.lineTo((float)line2.x2, (float)line2.y2);*/ p = new Point(); if (!getLineLineIntersection(line1, line2, p)) { p = null; } else { int dx = p.x - p2.x; int dy = p.y - p2.y; int distance = (int)Math.sqrt(dx * dx + dy * dy); if (distance > 10) { p.x = p2.x + dx / (distance / 10); p.y = p2.y + dy / (distance / 10); } } } } if (p != null && lastPoint != null) { drawSegment(g, mapView, path, lastPoint, p); } if (p != null) { lastPoint = p; } } if (p2 != null && p3 != null && lastPoint != null) { p3 = shiftPoint(p3, p2, -shift); drawSegment(g, mapView, path, lastPoint, p3); } return path; } private void drawSegment(Graphics2D g, NavigatableComponent nc, GeneralPath path, Point2D p1, Point2D p2) { boolean drawIt = isSegmentVisible(nc, p1, p2); if (drawIt) { /* draw segment line */ path.moveTo(p1.getX(), p1.getY()); path.lineTo(p2.getX(), p2.getY()); } } private boolean isSegmentVisible(NavigatableComponent nc, Point2D p1, Point2D p2) { if ((p1.getX() < 0) && (p2.getX() < 0)) return false; if ((p1.getY() < 0) && (p2.getY() < 0)) return false; if ((p1.getX() > nc.getWidth()) && (p2.getX() > nc.getWidth())) return false; if ((p1.getY() > nc.getHeight()) && (p2.getY() > nc.getHeight())) return false; return true; } }