package com.revolsys.swing.map.layer.openstreetmap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.identifier.Identifier;
import com.revolsys.record.io.format.openstreetmap.model.OsmConstants;
import com.revolsys.record.io.format.openstreetmap.model.OsmDocument;
import com.revolsys.record.io.format.openstreetmap.model.OsmElement;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.swing.map.layer.AbstractLayer;
import com.revolsys.swing.map.layer.record.AbstractRecordLayer;
import com.revolsys.swing.map.layer.record.LayerRecord;
import com.revolsys.util.Property;
import com.revolsys.util.number.Doubles;
public class OsmOverpassLayer extends AbstractRecordLayer {
private static final int TILE_SCALE_X = 50;
private static final int TILE_SCALE_Y = 50;
private static final double TILE_HEIGHT = 1.0 / TILE_SCALE_Y;
private static final double TILE_WIDTH = 1.0 / TILE_SCALE_X;
public static AbstractLayer newLayer(final Map<String, Object> properties) {
return new OsmOverpassLayer(properties);
}
private Map<BoundingBox, OsmDocument> boundingBoxTileMap = new HashMap<>();
private String serverUrl = "http://api.openstreetmap.org/";
public OsmOverpassLayer(final Map<String, Object> properties) {
super("openStreetMapVectorApi");
setProperties(properties);
}
@Override
public OsmOverpassLayer clone() {
final OsmOverpassLayer clone = (OsmOverpassLayer)super.clone();
clone.boundingBoxTileMap = new HashMap<>();
return clone;
}
@Override
public RecordDefinition getRecordDefinition() {
return OsmElement.RECORD_DEFINITION;
}
@Override
public List<LayerRecord> getRecords(BoundingBox boundingBox) {
if (hasGeometryField()) {
boundingBox = convertBoundingBox(boundingBox);
if (Property.hasValue(boundingBox)) {
final Map<Identifier, LayerRecord> recordMap = new HashMap<>();
final List<BoundingBox> boundingBoxes = getTileBoundingBoxes(boundingBox);
for (final BoundingBox tileBoundingBox : boundingBoxes) {
final OsmDocument document = getTile(tileBoundingBox);
for (final OsmElement record : document.getRecords()) {
final Geometry geometry = record.getGeometry();
if (geometry != null && !geometry.isEmpty()) {
if (boundingBox.intersects(geometry.getBoundingBox())) {
final Identifier identifier = record.getIdentifier();
// final OsmProxyLayerRecord layerRecord = new
// OsmProxyLayerRecord(
// this, document, identifier);
// recordMap.put(identifier, layerRecord);
}
}
}
}
this.boundingBoxTileMap.keySet().retainAll(boundingBoxes);
return new ArrayList<>(recordMap.values());
}
}
return Collections.emptyList();
}
public String getServerUrl() {
return this.serverUrl;
}
private synchronized OsmDocument getTile(final BoundingBox boundingBox) {
OsmDocument document = this.boundingBoxTileMap.get(boundingBox);
if (document == null) {
document = OsmDocument.newDocument(this.serverUrl, boundingBox);
this.boundingBoxTileMap.put(boundingBox, document);
}
return document;
}
public List<BoundingBox> getTileBoundingBoxes(BoundingBox boundingBox) {
boundingBox = boundingBox.convert(OsmConstants.WGS84_2D);
final List<BoundingBox> boundingBoxes = new ArrayList<>();
final double minX = Math.floor(boundingBox.getMinX() * TILE_SCALE_X) / TILE_SCALE_X;
final double minY = Math.floor(boundingBox.getMinY() * TILE_SCALE_Y) / TILE_SCALE_Y;
final double maxX = Math.ceil(boundingBox.getMaxX() * TILE_SCALE_X) / TILE_SCALE_X;
final double maxY = Math.ceil(boundingBox.getMaxY() * TILE_SCALE_Y) / TILE_SCALE_Y;
int indexY = 0;
for (double y = minY; y < maxY;) {
int indexX = 0;
indexY++;
final double nextY = Doubles.makePrecise(TILE_SCALE_Y, minY + indexY * TILE_HEIGHT);
for (double x = minX; x < maxX;) {
indexX++;
final double nextX = Doubles.makePrecise(TILE_SCALE_X, minX + indexX * TILE_WIDTH);
final BoundingBox tileBoundingBox = OsmConstants.WGS84_2D.newBoundingBox(x, y, nextX,
nextY);
boundingBoxes.add(tileBoundingBox);
x = nextX;
}
y = nextY;
}
return boundingBoxes;
}
public void setServerUrl(final String serverUrl) {
this.serverUrl = serverUrl;
}
}