001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.awt.Rectangle; 005import java.awt.geom.Area; 006import java.awt.geom.Path2D; 007import java.util.Collection; 008 009import org.openstreetmap.josm.data.coor.LatLon; 010import org.openstreetmap.josm.data.osm.BBox; 011import org.openstreetmap.josm.data.osm.Relation; 012import org.openstreetmap.josm.data.osm.Way; 013 014/** 015 * Implementation of simple boolean {@link GeoProperty}. 016 */ 017public class DefaultGeoProperty implements GeoProperty<Boolean> { 018 019 private final Area area; 020 private LatLon random; 021 022 /** 023 * Create DefaultGeoProperty based on a collection of closed ways. 024 * 025 * @param ways the ways forming the area 026 */ 027 public DefaultGeoProperty(Collection<Way> ways) { 028 Path2D path = new Path2D.Double(); 029 path.setWindingRule(Path2D.WIND_EVEN_ODD); 030 for (Way w : ways) { 031 Geometry.buildPath2DLatLon(w.getNodes(), path); 032 } 033 this.area = new Area(path); 034 } 035 036 /** 037 * Create DefaultGeoProperty based on a multipolygon relation. 038 * 039 * @param multipolygon the multipolygon 040 */ 041 public DefaultGeoProperty(Relation multipolygon) { 042 this.area = Geometry.getAreaLatLon(multipolygon); 043 } 044 045 @Override 046 public Boolean get(LatLon ll) { 047 return area.contains(ll.lon(), ll.lat()); 048 } 049 050 @Override 051 public Boolean get(BBox box) { 052 Area abox = new Area(box.toRectangle()); 053 Geometry.PolygonIntersection is = Geometry.polygonIntersection(abox, area, 1e-10 /* using deg and not meters */); 054 switch (is) { 055 case FIRST_INSIDE_SECOND: 056 return Boolean.TRUE; 057 case OUTSIDE: 058 return Boolean.FALSE; 059 default: 060 return null; 061 } 062 } 063 064 /** 065 * Returns the area. 066 * @return the area 067 * @since 14484 068 */ 069 public final Area getArea() { 070 return area; 071 } 072 073 /** 074 * Returns a random lat/lon in the area. 075 * @return a random lat/lon in the area 076 * @since 15359 077 */ 078 public final synchronized LatLon getRandomLatLon() { 079 if (random == null) { 080 Rectangle r = area.getBounds(); 081 double x, y; 082 do { 083 x = r.getX() + r.getWidth() * Math.random(); 084 y = r.getY() + r.getHeight() * Math.random(); 085 } while (!area.contains(x, y)); 086 087 random = new LatLon(y, x); 088 } 089 return random; 090 } 091}