Added methods to calculate optimal map size given a geo boundary.

- From zoom level 20 to 1, once find a size that contains the whole boundary, then the size will be used to retrieve map image from google

#story[928]
This commit is contained in:
Haoming Yin
2017-05-15 19:57:23 +12:00
parent 4fe4ac1079
commit 8f93956ff1
6 changed files with 75 additions and 24 deletions
+51 -13
View File
@@ -7,18 +7,25 @@ import java.net.URL;
import java.lang.Math;
/**
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
* By passing a rectangle like geo boundary, it returns a map image with the
* highest resolution. However, due to free quote account usage limit, the maximum
* resolution is only 1280 * 1280.
*
* Created by Haoming on 15/5/2017
*/
public class CanvasMap {
private Boundary bound;
private double width, height; // desired image size
private Boundary boundary;
private long width, height; // desired image size
private int zoom;
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
public CanvasMap(Boundary bound, double width, double height) {
this.bound = bound;
this.width = width;
this.height = height;
public CanvasMap(Boundary boundary) {
this.boundary = boundary;
calculateOptimalMapSize();
}
public Image getMapImage() {
@@ -35,33 +42,64 @@ public class CanvasMap {
}
private String getRequest() {
zoom = 15;
StringBuilder sb = new StringBuilder();
sb.append("https://maps.googleapis.com/maps/api/staticmap?");
sb.append(String.format("center=%f,%f", bound.getCentreLat(), bound.getCentreLng()));
sb.append(String.format("center=%f,%f", boundary.getCentreLat(), boundary.getCentreLng()));
sb.append(String.format("&zoom=%d", zoom));
sb.append(String.format("&size=%.0fx%.0f&scale=2", width / 2, height / 2));
sb.append(String.format("&size=%dx%d&scale=2", width, height));
sb.append("&style=feature:all|element:labels|visibility:off"); // hide all labels on map
// sb.append(String.format("&markers=%f,%f", boundary.getSouthLat(), boundary.getWestLng()));
// sb.append(String.format("&key=%s", KEY));
return sb.toString();
}
private void calculateOptimalMapSize() {
for (int z = 20; z > 0; z--) {
MapSize mapSize = getMapSize(z, boundary);
zoom = z;
width = mapSize.width;
height = mapSize.height;
// if map size is valid, exit the loop as we have the highest resolution
if (mapSize.isValid()) break;
}
}
private MapSize getMapSize(int zoom, Boundary boundary) {
double scale = Math.pow(2, zoom);
MapGeo geoSW = new MapGeo(boundary.getSouthLat(), boundary.getWestLng());
MapGeo geoNE = new MapGeo(boundary.getNorthLat(), boundary.getEastLng());
MapPoint pointSW = MercatorProjection.toMapPoint(geoSW);
MapPoint pointNE = MercatorProjection.toMapPoint(geoNE);
return new MapSize(Math.abs(pointNE.getX() - pointSW.getX()),
Math.abs(pointNE.getY() - pointSW.getY()));
return new MapSize(Math.abs(pointNE.getX() - pointSW.getX()) * scale,
Math.abs(pointNE.getY() - pointSW.getY()) * scale);
}
class MapSize {
long width, height;
MapSize(double width, double height) {
this.width = (long) width;
this.height = (long) height;
this.width = Math.round(width);
this.height = Math.round(height);
}
/**
* Map size is valid when width and height are both less than 640 pixels
* @return true if both dimensions are less than 640px
*/
boolean isValid() {
return Math.max(width, height) <= 640;
}
}
public long getWidth() {
return width;
}
public long getHeight() {
return height;
}
public int getZoom() {
return zoom;
}
}