diff --git a/src/main/java/seng302/models/map/Boundary.java b/src/main/java/seng302/models/map/Boundary.java index d39a60f0..4396d95d 100644 --- a/src/main/java/seng302/models/map/Boundary.java +++ b/src/main/java/seng302/models/map/Boundary.java @@ -1,9 +1,9 @@ package seng302.models.map; /** - * The Boundary class represents a square territorial bound on a map. It contains - * four extremity double values(N, E, S, W). N and S are represented as latitudes - * in radians. E and W are represented as longitudes in radians. + * The Boundary class represents a rectangle territorial boundary on a map. It + * contains four extremity double values(N, E, S, W). N and S are represented as + * latitudes in radians. E and W are represented as longitudes in radians. * * Created by Haoming on 10/5/17 */ @@ -18,27 +18,27 @@ public class Boundary { this.westLng = westLng; } - public double getCentreLat() { + double getCentreLat() { return (northLat + southLat) / 2; } - public double getCentreLng() { + double getCentreLng() { return (eastLng + westLng) / 2; } - public double getNorthLat() { + double getNorthLat() { return northLat; } - public double getEastLng() { + double getEastLng() { return eastLng; } - public double getSouthLat() { + double getSouthLat() { return southLat; } - public double getWestLng() { + double getWestLng() { return westLng; } } diff --git a/src/main/java/seng302/models/map/CanvasMap.java b/src/main/java/seng302/models/map/CanvasMap.java index 104bb219..3302112c 100644 --- a/src/main/java/seng302/models/map/CanvasMap.java +++ b/src/main/java/seng302/models/map/CanvasMap.java @@ -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; + } } diff --git a/src/main/java/seng302/models/map/MapGeo.java b/src/main/java/seng302/models/map/MapGeo.java index 96af1dd5..43d02565 100644 --- a/src/main/java/seng302/models/map/MapGeo.java +++ b/src/main/java/seng302/models/map/MapGeo.java @@ -1,5 +1,9 @@ package seng302.models.map; +/** + * A class represent Geo location (latitude, longitude). + * Created by Haoming on 15/5/2017 + */ class MapGeo { private double lat, lng; diff --git a/src/main/java/seng302/models/map/MapPoint.java b/src/main/java/seng302/models/map/MapPoint.java index aa0e55d0..41be919a 100644 --- a/src/main/java/seng302/models/map/MapPoint.java +++ b/src/main/java/seng302/models/map/MapPoint.java @@ -1,5 +1,9 @@ package seng302.models.map; +/** + * A class represent euclidean planar point (x, y) + * Created by Haoming on 15/5/2017 + */ class MapPoint { private double x, y; diff --git a/src/main/java/seng302/models/map/MercatorProjection.java b/src/main/java/seng302/models/map/MercatorProjection.java index 915712ba..b4bf647d 100644 --- a/src/main/java/seng302/models/map/MercatorProjection.java +++ b/src/main/java/seng302/models/map/MercatorProjection.java @@ -1,5 +1,10 @@ package seng302.models.map; +/** + * An utility class useful to convert between Geo locations and Mercator projection + * planar coordinates. + * Created by Haoming on 15/5/2017 + */ public class MercatorProjection { private static final double MERCATOR_RANGE = 256; diff --git a/src/main/java/seng302/models/map/TestMapController.java b/src/main/java/seng302/models/map/TestMapController.java index 6d656231..fc319bcc 100644 --- a/src/main/java/seng302/models/map/TestMapController.java +++ b/src/main/java/seng302/models/map/TestMapController.java @@ -17,7 +17,7 @@ public class TestMapController implements Initializable{ public void initialize(URL location, ResourceBundle resources) { GraphicsContext gc = mapCanvas.getGraphicsContext2D(); Boundary bound = new Boundary(57.662943, 11.848501, 57.673945, 11.824966); - CanvasMap canvasMap = new CanvasMap(bound, 1280, 960); - gc.drawImage(canvasMap.getMapImage(), 0, 0, 1280, 960); + CanvasMap canvasMap = new CanvasMap(bound); + gc.drawImage(canvasMap.getMapImage(), 0, 0, canvasMap.getWidth(), canvasMap.getHeight()); } }