package com.revolsys.swing.map.layer.bing;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.revolsys.collection.map.MapEx;
import com.revolsys.datatype.DataType;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.logging.Logs;
import com.revolsys.parallel.ExecutorServiceFactory;
import com.revolsys.swing.Icons;
import com.revolsys.swing.SwingUtil;
import com.revolsys.swing.component.ValueField;
import com.revolsys.swing.field.ComboBox;
import com.revolsys.swing.layout.GroupLayouts;
import com.revolsys.swing.map.Viewport2D;
import com.revolsys.swing.map.layer.AbstractTiledImageLayer;
import com.revolsys.swing.map.layer.BaseMapLayerGroup;
import com.revolsys.swing.map.layer.MapTile;
import com.revolsys.swing.menu.MenuFactory;
import com.revolsys.swing.menu.Menus;
import com.revolsys.util.CaseConverter;
public class BingLayer extends AbstractTiledImageLayer {
public static final GeometryFactory GEOMETRY_FACTORY = GeometryFactory.floating3(4326);
private static final BoundingBox MAX_BOUNDING_BOX = GEOMETRY_FACTORY.newBoundingBox(-180, -85,
180, 85);
private static void actionAddLayer(final BaseMapLayerGroup parent) {
final ValueField dialog = new ValueField();
dialog.setTitle("Add Bing Layer");
dialog.setIconImage("bing");
SwingUtil.addLabel(dialog, "Imagery Set");
final ComboBox<ImagerySet> imagerySetField = ComboBox.newComboBox("imagerySet", ImagerySet.Road,
ImagerySet.Aerial, ImagerySet.AerialWithLabels, ImagerySet.CollinsBart,
ImagerySet.OrdnanceSurvey);
dialog.add(imagerySetField);
GroupLayouts.makeColumns(dialog, 2, true, true);
dialog.setSaveAction(() -> {
final BingLayer layer = new BingLayer();
final ImagerySet imagerySet = imagerySetField.getSelectedItem();
layer.setImagerySet(imagerySet);
layer.setVisible(true);
parent.addLayer(layer);
});
dialog.showDialog();
}
public static void mapObjectFactoryInit() {
final MenuFactory baseMapsMenu = MenuFactory.getMenu(BaseMapLayerGroup.class);
Menus.addMenuItem(baseMapsMenu, "group", "Add Bing Layer", "bing", BingLayer::actionAddLayer,
false);
}
private BingClient client;
private ImagerySet imagerySet = ImagerySet.Road;
private MapLayer mapLayer;
private BingLayer() {
super("bing");
setIcon(Icons.getIcon("bing"));
}
public BingLayer(final Map<String, Object> properties) {
this();
setProperties(properties);
}
@Override
public boolean equals(final Object other) {
if (other instanceof BingLayer) {
final BingLayer layer = (BingLayer)other;
if (DataType.equal(layer.getImagerySet(), getImagerySet())) {
if (DataType.equal(layer.getMapLayer(), getMapLayer())) {
return true;
}
}
}
return false;
}
@Override
public BoundingBox getBoundingBox() {
return MAX_BOUNDING_BOX;
}
public BingClient getClient() {
return this.client;
}
public ImagerySet getImagerySet() {
return this.imagerySet;
}
public MapLayer getMapLayer() {
return this.mapLayer;
}
@Override
public List<MapTile> getOverlappingMapTiles(final Viewport2D viewport) {
final List<MapTile> tiles = new ArrayList<>();
try {
final double metresPerPixel = viewport.getUnitsPerPixel();
final int zoomLevel = this.client.getZoomLevel(metresPerPixel);
final double resolution = getResolution(viewport);
final BoundingBox geographicBoundingBox = viewport.getBoundingBox()
.convert(GEOMETRY_FACTORY)
.intersection(MAX_BOUNDING_BOX);
final double minX = geographicBoundingBox.getMinX();
final double minY = geographicBoundingBox.getMinY();
final double maxX = geographicBoundingBox.getMaxX();
final double maxY = geographicBoundingBox.getMaxY();
// Tiles start at the North-West corner of the map
final int minTileY = this.client.getTileY(zoomLevel, maxY);
final int maxTileY = this.client.getTileY(zoomLevel, minY);
final int minTileX = this.client.getTileX(zoomLevel, minX);
final int maxTileX = this.client.getTileX(zoomLevel, maxX);
for (int tileY = minTileY; tileY <= maxTileY; tileY++) {
for (int tileX = minTileX; tileX <= maxTileX; tileX++) {
final BingMapTile tile = new BingMapTile(this, zoomLevel, resolution, tileX, tileY);
tiles.add(tile);
}
}
} catch (final Throwable e) {
Logs.error(this, "Error getting tile envelopes", e);
}
return tiles;
}
@Override
public double getResolution(final Viewport2D viewport) {
final double metresPerPixel = viewport.getUnitsPerPixel();
final int zoomLevel = this.client.getZoomLevel(metresPerPixel);
return this.client.getResolution(zoomLevel);
}
@Override
protected boolean initializeDo() {
final String bingMapsKey = getProperty("bingMapsKey");
this.client = new BingClient(bingMapsKey);
return true;
}
public void setClient(final BingClient client) {
this.client = client;
ExecutorServiceFactory.getExecutorService().execute(this::initialize);
}
public void setImagerySet(final ImagerySet imagerySet) {
this.imagerySet = imagerySet;
if (getName() == null) {
setName("Bing " + CaseConverter.toCapitalizedWords(imagerySet.toString()));
}
}
public void setMapLayer(final MapLayer mapLayer) {
this.mapLayer = mapLayer;
}
@Override
public MapEx toMap() {
final MapEx map = super.toMap();
addToMap(map, "imagerySet", this.imagerySet);
addToMap(map, "mapLayer", this.mapLayer);
return map;
}
}