/** * */ package com.tilusnet.josm.plugins.alignways; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.awt.geom.Line2D; import java.util.Collection; import java.util.HashSet; import java.util.Objects; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.WaySegment; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.layer.MapViewPaintable; /** * @author tilusnet <tilusnet@gmail.com> * */ public class AlignWaysSegment implements MapViewPaintable { protected WaySegment segment; protected MapView mapview; protected Color segmentColor = Color.WHITE; protected Collection<Node> segmentEndPoints; public AlignWaysSegment(MapView mapview, Point p) throws IllegalArgumentException { if (mapview == null) throw new IllegalArgumentException(tr( "Parameter ''{0}'' must not be null", "mapview")); if (p == null) throw new IllegalArgumentException(tr( "Parameter ''{0}'' must not be null", "p")); this.mapview = mapview; } void setSegment(WaySegment segment) { this.segment = segment; if (segment != null) { setSegmentEndpoints(segment); mapview.addTemporaryLayer(this); } } void setSegmentEndpoints(WaySegment segment) { if (segment != null) { try { segmentEndPoints = new HashSet<>(); segmentEndPoints.add(segment.getFirstNode()); segmentEndPoints.add(segment.getSecondNode()); } catch (IndexOutOfBoundsException e) { Main.error(e); } } } protected WaySegment getNearestWaySegment(Point p) { return mapview.getNearestWaySegment(p, OsmPrimitive::isUsable); } public void destroy() { if (segment != null) { mapview.removeTemporaryLayer(this); } } public WaySegment getSegment() { return segment; } public Collection<Node> getSegmentEndPoints() { return segmentEndPoints; } @Override public void paint(Graphics2D g, MapView mv, Bounds bbox) { // Note: segment should never be null here, and its nodes should never be missing. // If they are, it's a bug, possibly related to tracking of DataSet deletions. if (segment.way.getNodesCount() <= segment.lowerIndex + 1) { Main.warn("Not drawing AlignWays highlighting segment: underlying nodes disappeared"); return; } highlightSegment(segmentColor, g, mv); } protected void highlightSegment(Color c, Graphics2D g, MapView mv) { g.setColor(c); g.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawSegment(g, mv); } protected void drawSegment(Graphics2D g, MapView mv) { try { Node n1 = segment.getFirstNode(); Node n2 = segment.getSecondNode(); g.draw(new Line2D.Double(mv.getPoint(n1), mv.getPoint(n2))); } catch (IndexOutOfBoundsException e) { Main.error(e); } } protected boolean containsPrimitive(OsmPrimitive primitive) { if (segment == null) return false; return (primitive instanceof Way && segment.way.equals(primitive)) || (primitive instanceof Node && segmentEndPoints.contains(primitive)); } @Override public int hashCode() { if (segment == null) { return System.identityHashCode(this); } // hashCode and equals should be consistent during the lifetime of this segment, // otherwise the temporary mapview overlay will not be properly removed on destroy() return segment.hashCode(); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof AlignWaysSegment)) return false; AlignWaysSegment that = (AlignWaysSegment) o; return Objects.equals(segment, that.segment); } }