package com.bbn.openmap.proj; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.geom.Point2D; import java.util.ArrayList; /** * A Projection that wraps another projection, but stretch the image to another * aspect ratio. * <p> * The motivation for this projection is to support the following clause in wms * 1.1.1. * <p> * OGC 01-068r3 (wms 1.1.1) 7.2.3.8. "In the case where the aspect ratio of the * BBOX and the ratio width/height are different, the WMS shall stretch the * returned map so that the resulting pixels could themselves be rendered in the * aspect ratio of the BBOX" * * @author halset */ public class AspectRatioProjection extends GeoProj { private GeoProj wrappedProjection; private float xFactor; private float yFactor; private float halfWidth; private float halfWrappedWidth; private float halfHeight; private float halfWrappedHeight; private boolean xHasFactor; private boolean yHasFactor; /** * Constructor that takes a projection and the new width/height. * * @param proj a projection to wrap * @param w a int with the new width * @param h a int with the new height */ public AspectRatioProjection(GeoProj proj, int w, int h) { super(proj.getCenter(), proj.getScale(), w, h); wrappedProjection = proj; xHasFactor = proj.getWidth() != w; yHasFactor = proj.getHeight() != h; computeParameters(); } private Point2D fromWrapped(Point2D pt) { pt.setLocation(xFromWrapped((float) pt.getX()), yFromWrapped((float) pt.getY())); return pt; } private float xFromWrapped(float x) { if (!xHasFactor) return x; return ((x - halfWrappedWidth) * xFactor + halfWidth); } private float yFromWrapped(float y) { if (!yHasFactor) return y; return ((y - halfWrappedHeight) * yFactor + halfHeight); } private float xToWrapped(float x) { if (!xHasFactor) return x; return ((x - halfWidth) / xFactor + halfWrappedWidth); } private float yToWrapped(float y) { if (!yHasFactor) return y; return ((y - halfHeight) / yFactor + halfWrappedHeight); } protected ArrayList<float[]> _forwardPoly(float[] rawllpts, int ltype, int nsegs, boolean isFilled) { ArrayList<float[]> stuff = wrappedProjection._forwardPoly(rawllpts, ltype, nsegs, isFilled); int size = stuff.size(); for (int i = 0; i < size; i += 2) { float[] xpts = stuff.get(i); if (xHasFactor) { for (int j = 0; j < xpts.length; j++) xpts[j] = xFromWrapped(xpts[j]); } if (yHasFactor) { float[] ypts = stuff.get(i + 1); for (int j = 0; j < ypts.length; j++) ypts[j] = yFromWrapped(ypts[j]); } } return stuff; } protected void computeParameters() { if (wrappedProjection != null) { wrappedProjection.computeParameters(); xFactor = (float) ((double) getWidth() / (double) wrappedProjection.getWidth()); yFactor = (float) ((double) getHeight() / (double) wrappedProjection.getHeight()); halfWidth = (float) getWidth() / 2.0F; halfHeight = (float) getHeight() / 2.0F; halfWrappedWidth = (float) wrappedProjection.getWidth() / 2.0F; halfWrappedHeight = (float) wrappedProjection.getHeight() / 2.0F; } } public void drawBackground(Graphics2D g, Paint p) { wrappedProjection.drawBackground(g, p); } public void drawBackground(Graphics g) { wrappedProjection.drawBackground(g); } public double normalizeLatitude(double lat) { if (wrappedProjection == null) { if (lat > NORTH_POLE) { return NORTH_POLE; } else if (lat < SOUTH_POLE) { return SOUTH_POLE; } return lat; } return wrappedProjection.normalizeLatitude(lat); } @Override public Point2D forward(Point2D llp, Point2D pt) { return fromWrapped(wrappedProjection.forward(llp, pt)); } @Override public Point2D forward(double lat, double lon, Point2D pt) { return fromWrapped(wrappedProjection.forward(lat, lon, pt)); } public boolean forwardRaw(float[] rawllpts, int rawoff, float[] xcoords, float[] ycoords, boolean[] visible, int copyoff, int copylen) { boolean r = wrappedProjection.forwardRaw(rawllpts, rawoff, xcoords, ycoords, visible, copyoff, copylen); int end = copylen + copyoff; for (int i = copyoff; i < end; i++) { if (xHasFactor) xcoords[i] = xFromWrapped(xcoords[i]); if (yHasFactor) ycoords[i] = yFromWrapped(ycoords[i]); } return r; } public Point2D getLowerRight() { return wrappedProjection.getLowerRight(); } public Point2D getUpperLeft() { return wrappedProjection.getUpperLeft(); } @Override public Point2D inverse(Point2D point, Point2D llpt) { return inverse(point.getX(), point.getY(), llpt); } @Override protected ArrayList<float[]> _forwardPoly(double[] rawllpts, int ltype, int nsegs, boolean isFilled) { ArrayList<float[]> stuff = wrappedProjection._forwardPoly(rawllpts, ltype, nsegs, isFilled); int size = stuff.size(); for (int i = 0; i < size; i += 2) { float[] xpts = stuff.get(i); if (xHasFactor) { for (int j = 0; j < xpts.length; j++) xpts[j] = xFromWrapped(xpts[j]); } if (yHasFactor) { float[] ypts = stuff.get(i + 1); for (int j = 0; j < ypts.length; j++) ypts[j] = yFromWrapped(ypts[j]); } } return stuff; } @Override public Point2D forward(double lat, double lon, Point2D pt, boolean isRadian) { return fromWrapped(wrappedProjection.forward(lat, lon, pt, isRadian)); } @Override public Point2D inverse(double x, double y, Point2D llpt) { return wrappedProjection.inverse(xToWrapped((float) x), yToWrapped((float) y), llpt); } public boolean isPlotable(double lat, double lon) { return wrappedProjection.isPlotable(lat, lon); } }