001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.utils; 003 004import java.awt.Graphics2D; 005import java.awt.Point; 006import java.awt.Rectangle; 007import java.awt.Shape; 008import java.awt.geom.Area; 009import java.awt.geom.Path2D; 010 011import org.openstreetmap.josm.data.Bounds; 012import org.openstreetmap.josm.gui.MapView; 013import org.openstreetmap.josm.gui.NavigatableComponent; 014import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 015import org.openstreetmap.josm.plugins.streetside.StreetsideSequence; 016 017/** 018 * Utility class to convert entities like {@link Bounds} and {@link StreetsideSequence} into {@link Shape}s that 019 * can then easily be drawn on a {@link MapView}s {@link Graphics2D}-context. 020 */ 021public final class MapViewGeometryUtil { 022 private MapViewGeometryUtil() { 023 // Private constructor to avoid instantiation 024 } 025 026 /** 027 * Subtracts the download bounds from the rectangular bounds of the map view. 028 * @param mv the MapView that is used for the LatLon-to-Point-conversion and that determines 029 * the Bounds from which the downloaded Bounds are subtracted 030 * @param downloadBounds multiple {@link Bounds} objects that represent the downloaded area 031 * @return the difference between the {@link MapView}s bounds and the downloaded area 032 */ 033 public static Area getNonDownloadedArea(MapView mv, Iterable<Bounds> downloadBounds) { 034 Rectangle b = mv.getBounds(); 035 // on some platforms viewport bounds seem to be offset from the left, 036 // over-grow it just to be sure 037 b.grow(100, 100); 038 Area a = new Area(b); 039 // now successively subtract downloaded areas 040 for (Bounds bounds : downloadBounds) { 041 Point p1 = mv.getPoint(bounds.getMin()); 042 Point p2 = mv.getPoint(bounds.getMax()); 043 Rectangle r = new Rectangle(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), 044 Math.abs(p2.x - p1.x), Math.abs(p2.y - p1.y)); 045 a.subtract(new Area(r)); 046 } 047 return a; 048 } 049 050 /** 051 * Converts a {@link StreetsideSequence} into a {@link Path2D} that can be drawn 052 * on the specified {@link NavigatableComponent}'s {@link Graphics2D}-context. 053 * @param nc the {@link NavigatableComponent} for which this conversion should be performed, typically a {@link MapView} 054 * @param seq the sequence to convert 055 * @return the {@link Path2D} object to which the {@link StreetsideSequence} has been converted 056 */ 057 public static Path2D getSequencePath(NavigatableComponent nc, StreetsideSequence seq) { 058 final Path2D.Double path = new Path2D.Double(); 059 seq.getImages().stream().filter(StreetsideAbstractImage::isVisible).forEach(img -> { 060 Point p = nc.getPoint(img.getMovingLatLon()); 061 if (path.getCurrentPoint() == null) { 062 path.moveTo(p.getX(), p.getY()); 063 } else { 064 path.lineTo(p.getX(), p.getY()); 065 } 066 }); 067 return path; 068 } 069}