package org.geotools.renderer.crs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.List; import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.io.WKTReader; public class ProjectionHandlerTest { static final double EPS = 1e-6; static CoordinateReferenceSystem WGS84; static CoordinateReferenceSystem UTM32N; static CoordinateReferenceSystem MERCATOR; static CoordinateReferenceSystem MERCATOR_SHIFTED; @BeforeClass public static void setup() throws Exception { WGS84 = DefaultGeographicCRS.WGS84; UTM32N = CRS.decode("EPSG:32632", true); MERCATOR_SHIFTED = CRS.decode("EPSG:3349", true); MERCATOR = CRS.decode("EPSG:3395", true); } @Test public void testQueryWrappingWGS84() throws Exception { ReferencedEnvelope wgs84Envelope = new ReferencedEnvelope(-190, 60, -90, 45, WGS84); ProjectionHandler handler = ProjectionHandlerFinder.getHandler(wgs84Envelope, true); assertNull(handler.validArea); List<ReferencedEnvelope> envelopes = handler.getQueryEnvelopes(DefaultGeographicCRS.WGS84); assertEquals(2, envelopes.size()); ReferencedEnvelope expected = new ReferencedEnvelope(170, 180, -90, 45, WGS84); assertTrue(envelopes.remove(wgs84Envelope)); assertEquals(expected, envelopes.get(0)); } @Test public void testValidAreaMercator() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(-180, 180, -89.9999, 89.9999, WGS84); ReferencedEnvelope mercatorEnvelope = world.transform(MERCATOR_SHIFTED, true); // check valid area ProjectionHandler handler = ProjectionHandlerFinder.getHandler(mercatorEnvelope, true); ReferencedEnvelope va = handler.validArea; assertNotNull(va); assertEquals(WGS84, va.getCoordinateReferenceSystem()); assertTrue(va.getMinX() <= -180.0); assertTrue(va.getMaxX() >= 180.0); assertTrue(-90 < va.getMinY()); assertTrue(90.0 > va.getMaxY()); } @Test public void testQueryWrappingMercatorWorld() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(-200, 200, -89, 89, WGS84); ReferencedEnvelope mercatorEnvelope = world.transform(MERCATOR_SHIFTED, true); // get query area, we expect just one envelope spanning the whole world ProjectionHandler handler = ProjectionHandlerFinder.getHandler(mercatorEnvelope, true); List<ReferencedEnvelope> envelopes = handler.getQueryEnvelopes(DefaultGeographicCRS.WGS84); assertEquals(1, envelopes.size()); ReferencedEnvelope env = envelopes.get(0); assertEquals(-180.0, env.getMinX(), EPS); assertEquals(180.0, env.getMaxX(), EPS); assertEquals(-89, env.getMinY(), 0.1); assertEquals(89.0, env.getMaxY(), 0.1); } @Test public void testQueryWrappingMercatorSeparate() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(160, 180, -40, 40, WGS84); ReferencedEnvelope mercatorEnvelope = world.transform(MERCATOR, true); // move it so that it crosses the dateline mercatorEnvelope.translate(mercatorEnvelope.getWidth() / 2, 0); // get query area, we expect two separate query envelopes, the original and the ProjectionHandler handler = ProjectionHandlerFinder.getHandler(mercatorEnvelope, true); List<ReferencedEnvelope> envelopes = handler.getQueryEnvelopes(DefaultGeographicCRS.WGS84); assertEquals(2, envelopes.size()); ReferencedEnvelope reOrig = envelopes.get(0); // original assertEquals(170.0, reOrig.getMinX(), EPS); assertEquals(190.0, reOrig.getMaxX(), EPS); ReferencedEnvelope reAdded = envelopes.get(1); // added assertEquals(-180.0, reAdded.getMinX(), EPS); assertEquals(-170.0, reAdded.getMaxX(), EPS); } @Test public void testValidAreaUTM() throws Exception { ReferencedEnvelope wgs84Envelope = new ReferencedEnvelope(8, 10, 40, 45, WGS84); ReferencedEnvelope utmEnvelope = wgs84Envelope.transform(UTM32N, true); // check valid area ProjectionHandler handler = ProjectionHandlerFinder.getHandler(utmEnvelope, true); ReferencedEnvelope va = handler.validArea; assertNotNull(va); assertEquals(WGS84, va.getCoordinateReferenceSystem()); assertTrue(9 - 90 < va.getMinX() && va.getMinX() <= 9 - 3); assertTrue(9 + 3 <= va.getMaxX() && va.getMaxX() < 9 + 90); assertEquals(-90, va.getMinY(), EPS); assertEquals(90.0, va.getMaxY(), EPS); } @Test public void testQueryUTM() throws Exception { ReferencedEnvelope wgs84Envelope = new ReferencedEnvelope(8, 10, 40, 45, WGS84); ReferencedEnvelope utmEnvelope = wgs84Envelope.transform(UTM32N, true); // get query area, we expect just one envelope, the original one ProjectionHandler handler = ProjectionHandlerFinder.getHandler(utmEnvelope, true); ReferencedEnvelope expected = utmEnvelope.transform(WGS84, true); List<ReferencedEnvelope> envelopes = handler.getQueryEnvelopes(DefaultGeographicCRS.WGS84); assertEquals(1, envelopes.size()); assertEquals(expected, envelopes.get(0)); } @Test public void testWrapGeometryMercator() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(160, 180, -40, 40, WGS84); ReferencedEnvelope mercatorEnvelope = world.transform(MERCATOR, true); // move it so that it crosses the dateline (measures are still accurate for something // crossing the dateline mercatorEnvelope.translate(mercatorEnvelope.getWidth() / 2, 0); // a geometry that will cross the dateline and sitting in the same area as the // rendering envelope Geometry g = new WKTReader().read("LINESTRING(170 -40, 190 40)"); // make sure the geometry is not wrapped ProjectionHandler handler = ProjectionHandlerFinder.getHandler(mercatorEnvelope, true); assertTrue(handler.requiresProcessing(WGS84, g)); Geometry preProcessed = handler.preProcess(WGS84, g); // no cutting expected assertEquals(g, preProcessed); // transform and post process Geometry transformed = JTS.transform(g, CRS.findMathTransform(WGS84, MERCATOR, true)); Geometry postProcessed = handler.postProcess(transformed); Envelope env = postProcessed.getEnvelopeInternal(); // check the geometry is in the same area as the rendering envelope assertEquals(mercatorEnvelope.getMinX(), env.getMinX(), EPS); assertEquals(mercatorEnvelope.getMaxX(), env.getMaxX(), EPS); } @Test public void testWrapGeometryWGS84() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(-180, 180, -90, 90, WGS84); // a geometry that will cross the dateline and sitting in the same area as the // rendering envelope Geometry g = new WKTReader().read("POLYGON((-178 -90, -178 90, 178 90, 178 -90, -178 -90))"); Geometry original = new WKTReader().read("POLYGON((-178 -90, -178 90, 178 90, 178 -90, -178 -90))"); // make sure the geometry is not wrapped, but it is preserved ProjectionHandler handler = ProjectionHandlerFinder.getHandler(world, true); assertTrue(handler.requiresProcessing(WGS84, g)); Geometry preProcessed = handler.preProcess(WGS84, g); // no cutting expected assertTrue(original.equals(preProcessed)); // post process Geometry postProcessed = handler.postProcess(g); // check the geometry is in the same area as the rendering envelope assertTrue(original.equals(postProcessed)); } @Test public void testWrapGeometryWGS84Duplicate() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(-200, 200, -90, 90, WGS84); // a geometry that will cross the dateline and sitting in the same area as the // rendering envelope Geometry g = new WKTReader().read("POLYGON((-178 -90, -178 90, 178 90, 178 -90, -178 -90))"); Geometry original = new WKTReader().read("POLYGON((-178 -90, -178 90, 178 90, 178 -90, -178 -90))"); // make sure the geometry is not wrapped, but it is preserved ProjectionHandler handler = ProjectionHandlerFinder.getHandler(world, true); assertTrue(handler.requiresProcessing(WGS84, g)); Geometry preProcessed = handler.preProcess(WGS84, g); // no cutting expected assertTrue(original.equals(preProcessed)); // post process Geometry postProcessed = handler.postProcess(g); // check we have replicated the geometry in both directions Envelope ppEnvelope = postProcessed.getEnvelopeInternal(); Envelope expected = new Envelope(-538, 538, -90, 90); assertEquals(expected, ppEnvelope); } @Test public void testDuplicateGeometryMercator() throws Exception { ReferencedEnvelope world = new ReferencedEnvelope(-180, 180, -50, 50, WGS84); ReferencedEnvelope mercatorEnvelope = world.transform(MERCATOR, true); // a geometry that will cross the dateline and sitting in the same area as the // rendering envelope Geometry g = new WKTReader().read("LINESTRING(170 -50, 190 50)"); // make sure the geometry is not wrapped ProjectionHandler handler = ProjectionHandlerFinder.getHandler(mercatorEnvelope, true); assertTrue(handler.requiresProcessing(WGS84, g)); Geometry preProcessed = handler.preProcess(WGS84, g); // no cutting expected assertEquals(g, preProcessed); // transform and post process Geometry transformed = JTS.transform(g, CRS.findMathTransform(WGS84, MERCATOR, true)); Geometry postProcessed = handler.postProcess(transformed); // should have been duplicated in two parts assertTrue(postProcessed instanceof MultiLineString); MultiLineString mls = (MultiLineString) postProcessed; assertEquals(2, mls.getNumGeometries()); // the two geometries width should be the same as 20° double twentyDegWidth = mercatorEnvelope.getWidth() / 18; assertEquals(twentyDegWidth, mls.getGeometryN(0).getEnvelopeInternal().getWidth(), EPS); assertEquals(twentyDegWidth, mls.getGeometryN(1).getEnvelopeInternal().getWidth(), EPS); } public void testCutGeometryUTM() throws Exception { ReferencedEnvelope wgs84Envelope = new ReferencedEnvelope(8, 10, 40, 45, WGS84); ReferencedEnvelope utmEnvelope = wgs84Envelope.transform(UTM32N, true); // a geometry that will definitely go outside of the UTM32N valid area Geometry g = new WKTReader().read("LINESTRING(-170 -40, 170, 40)"); ProjectionHandler handler = ProjectionHandlerFinder.getHandler(utmEnvelope, true); assertTrue(handler.requiresProcessing(UTM32N, g)); Geometry preProcessed = handler.preProcess(WGS84, g); assertTrue(!preProcessed.equals(g)); assertTrue(handler.validArea.contains(preProcessed.getEnvelopeInternal())); } }