From 80b4b1c7fc8d521709404a9c713f9fba180aeeb4 Mon Sep 17 00:00:00 2001 From: Holt59 Date: Wed, 21 Mar 2018 20:39:46 +0100 Subject: [PATCH] Fix drawing for very small graph and add new projection for fake maps. --- src/main/org/insa/graph/GraphStatistics.java | 25 +++++++ .../graphics/drawing/MercatorProjection.java | 58 ++++------------ .../drawing/PlateCarreProjection.java | 68 +++++++++++++++++++ .../org/insa/graphics/drawing/Projection.java | 51 ++++++++++++++ .../drawing/components/BasicDrawing.java | 15 ++-- 5 files changed, 170 insertions(+), 47 deletions(-) create mode 100644 src/main/org/insa/graphics/drawing/PlateCarreProjection.java create mode 100644 src/main/org/insa/graphics/drawing/Projection.java diff --git a/src/main/org/insa/graph/GraphStatistics.java b/src/main/org/insa/graph/GraphStatistics.java index 91c6e35..c90f24e 100644 --- a/src/main/org/insa/graph/GraphStatistics.java +++ b/src/main/org/insa/graph/GraphStatistics.java @@ -81,6 +81,31 @@ public class GraphStatistics { return this.extend(size, size, size, size); } + /** + * @param point Point to check + * + * @return true if this box contains the given point. + */ + public boolean contains(Point point) { + return this.bottomRight.getLatitude() <= point.getLatitude() + && this.topLeft.getLatitude() >= point.getLatitude() + && this.topLeft.getLongitude() <= point.getLongitude() + && this.bottomRight.getLongitude() >= point.getLongitude(); + } + + /** + * @return true if this box contains the given box. + */ + public boolean contains(BoundingBox other) { + return this.contains(other.bottomRight) && this.contains(other.topLeft); + } + + @Override + public String toString() { + return "BoundingBox(topLeft=" + this.topLeft + ", bottomRight=" + this.bottomRight + + ")"; + } + } // Bounding box for this graph. diff --git a/src/main/org/insa/graphics/drawing/MercatorProjection.java b/src/main/org/insa/graphics/drawing/MercatorProjection.java index f5facc5..e393507 100644 --- a/src/main/org/insa/graphics/drawing/MercatorProjection.java +++ b/src/main/org/insa/graphics/drawing/MercatorProjection.java @@ -4,7 +4,7 @@ import java.awt.Dimension; import org.insa.graph.GraphStatistics.BoundingBox; -public class MercatorProjection { +public class MercatorProjection implements Projection { public static final double MAX_LATITUDE = 82; @@ -49,20 +49,6 @@ public class MercatorProjection { this.height = imageDimension.getHeight(); } - /** - * @return Image width for this projection to work properly. - */ - public double getImageWidth() { - return this.width; - } - - /** - * @return Image weight for this projection to work properly. - */ - public double getImageHeight() { - return this.height; - } - /** * Compute the projection (without scaling) of the given latitude. * @@ -93,49 +79,35 @@ public class MercatorProjection { : new Dimension(maxSize, (int) (maxSize * propHeight / propWidth)); } - /** - * Project the given latitude on the image. - * - * @param latitude Latitude to project. - * - * @return Projected position of the latitude on the image. - */ + @Override + public double getImageWidth() { + return this.width; + } + + @Override + public double getImageHeight() { + return this.height; + } + + @Override public int latitudeToPixelY(float latitude) { return (int) ((this.maxLatitudeProj - projectY(latitude)) / (this.maxLatitudeProj - this.minLatitudeProj) * this.height); } - /** - * Project the given longitude on the image. - * - * @param longitude Longitude to project. - * - * @return Projected position of the longitude on the image. - */ + @Override public int longitudeToPixelX(float longitude) { return (int) (width * (longitude - minLongitude) / (maxLongitude - minLongitude)); } - /** - * Retrieve the latitude associated to the given projected point. - * - * @param py Projected y-position for which latitude should be retrieved. - * - * @return The original latitude of the point. - */ + @Override public float pixelYToLatitude(double py) { float y = (float) (this.maxLatitudeProj - (py / this.height) * (this.maxLatitudeProj - this.minLatitudeProj)); return (float) (180 * (2 * Math.atan(Math.exp(y)) - Math.PI / 2) / Math.PI); } - /** - * Retrieve the longitude associated to the given projected point. - * - * @param px Projected x-position for which longitude should be retrieved. - * - * @return The original longitude of the point. - */ + @Override public float pixelXToLongitude(double px) { return (float) ((px / this.width) * (this.maxLongitude - this.minLongitude) + this.minLongitude); diff --git a/src/main/org/insa/graphics/drawing/PlateCarreProjection.java b/src/main/org/insa/graphics/drawing/PlateCarreProjection.java new file mode 100644 index 0000000..bd3b9dd --- /dev/null +++ b/src/main/org/insa/graphics/drawing/PlateCarreProjection.java @@ -0,0 +1,68 @@ +package org.insa.graphics.drawing; + +import org.insa.graph.GraphStatistics.BoundingBox; + +public class PlateCarreProjection implements Projection { + + // Bounding box + private final float minLatitude, minLongitude, maxLatitude, maxLongitude; + + // Dimension of the image + private final double width, height; + + /** + * Create a new PlateCarreProjection corresponding to the given BoundingBox and + * maxSize. + * + * @param boundingBox Box for this projection. + * @param maxSize Maximum size of any side (width / height) of the image to + * which this projection should draw. + */ + public PlateCarreProjection(BoundingBox boundingBox, int maxSize) { + // Find minimum/maximum longitude and latitude. + this.minLongitude = boundingBox.getTopLeftPoint().getLongitude(); + this.maxLongitude = boundingBox.getBottomRightPoint().getLongitude(); + this.minLatitude = boundingBox.getBottomRightPoint().getLatitude(); + this.maxLatitude = boundingBox.getTopLeftPoint().getLatitude(); + + float diffLon = maxLongitude - minLongitude, diffLat = maxLatitude - minLatitude; + + this.width = diffLon < diffLat ? (int) (maxSize * diffLon / diffLat) : maxSize; + this.height = diffLon < diffLat ? maxSize : (int) (maxSize * diffLat / diffLon); + } + + @Override + public double getImageWidth() { + return this.width; + } + + @Override + public double getImageHeight() { + return this.height; + } + + @Override + public int latitudeToPixelY(float latitude) { + return (int) (this.height * (this.maxLatitude - latitude) + / (this.maxLatitude - this.minLatitude)); + } + + @Override + public int longitudeToPixelX(float longitude) { + return (int) (this.width * (longitude - this.minLongitude) + / (this.maxLongitude - this.minLongitude)); + } + + @Override + public float pixelYToLatitude(double py) { + return (float) (this.maxLatitude + - py / this.height * (this.maxLatitude - this.minLatitude)); + } + + @Override + public float pixelXToLongitude(double px) { + return (float) (px / this.width * (this.maxLongitude - this.minLongitude) + + this.minLongitude); + } + +} diff --git a/src/main/org/insa/graphics/drawing/Projection.java b/src/main/org/insa/graphics/drawing/Projection.java new file mode 100644 index 0000000..078991a --- /dev/null +++ b/src/main/org/insa/graphics/drawing/Projection.java @@ -0,0 +1,51 @@ +package org.insa.graphics.drawing; + +public interface Projection { + + /** + * @return Image width for this projection to work properly. + */ + public double getImageWidth(); + + /** + * @return Image weight for this projection to work properly. + */ + public double getImageHeight(); + + /** + * Project the given latitude on the image. + * + * @param latitude Latitude to project. + * + * @return Projected position of the latitude on the image. + */ + public int latitudeToPixelY(float latitude); + + /** + * Project the given longitude on the image. + * + * @param longitude Longitude to project. + * + * @return Projected position of the longitude on the image. + */ + public int longitudeToPixelX(float longitude); + + /** + * Retrieve the latitude associated to the given projected point. + * + * @param py Projected y-position for which latitude should be retrieved. + * + * @return The original latitude of the point. + */ + public float pixelYToLatitude(double py); + + /** + * Retrieve the longitude associated to the given projected point. + * + * @param px Projected x-position for which longitude should be retrieved. + * + * @return The original longitude of the point. + */ + public float pixelXToLongitude(double px); + +} diff --git a/src/main/org/insa/graphics/drawing/components/BasicDrawing.java b/src/main/org/insa/graphics/drawing/components/BasicDrawing.java index 902f314..506e800 100644 --- a/src/main/org/insa/graphics/drawing/components/BasicDrawing.java +++ b/src/main/org/insa/graphics/drawing/components/BasicDrawing.java @@ -32,6 +32,8 @@ import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.DrawingClickListener; import org.insa.graphics.drawing.GraphPalette; import org.insa.graphics.drawing.MercatorProjection; +import org.insa.graphics.drawing.PlateCarreProjection; +import org.insa.graphics.drawing.Projection; import org.insa.graphics.drawing.overlays.MarkerOverlay; import org.insa.graphics.drawing.overlays.MarkerUtils; import org.insa.graphics.drawing.overlays.Overlay; @@ -301,7 +303,7 @@ public class BasicDrawing extends JPanel implements Drawing { // Maximum width for the drawing (in pixels). private static final int MAXIMUM_DRAWING_WIDTH = 2000; - private MercatorProjection projection; + private Projection projection; // Width and height of the image private int width, height; @@ -573,8 +575,13 @@ public class BasicDrawing extends JPanel implements Drawing { float deltaLon = 0.01f * diffLon, deltaLat = 0.01f * diffLat; // Create the projection and retrieve width and height for the box. - projection = new MercatorProjection(box.extend(deltaLon, deltaLat, deltaLon, deltaLat), - MAXIMUM_DRAWING_WIDTH); + BoundingBox extendedBox = box.extend(deltaLon, deltaLat, deltaLon, deltaLat); + if (graph.getMapId().startsWith("0x")) { + projection = new PlateCarreProjection(extendedBox, MAXIMUM_DRAWING_WIDTH); + } + else { + projection = new MercatorProjection(extendedBox, MAXIMUM_DRAWING_WIDTH); + } this.width = (int) projection.getImageWidth(); this.height = (int) projection.getImageHeight(); @@ -605,7 +612,7 @@ public class BasicDrawing extends JPanel implements Drawing { @Override public void drawGraph(Graph graph, GraphPalette palette) { - int repaintModulo = graph.getNodes().size() / 100; + int repaintModulo = Math.max(1, graph.getNodes().size() / 100); // Initialize the buffered image