// Returns the tile for zoom which covers given lat/lon coordinates" private static Tile latLonToTile( final double lat, final double lon, final int zoom, final int tilesize, final boolean excludeEdge) { final Pixel p = latLonToPixels(lat, lon, zoom, tilesize); if (excludeEdge) { TMSUtils.Tile tile = TMSUtils.pixelsToTile(p.px, p.py, tilesize); final TMSUtils.Tile t = TMSUtils.pixelsToTile(p.px - 1, p.py - 1, tilesize); // lon is on an x tile boundary, so we'll move it to the left if (t.tx < tile.tx) { tile = new TMSUtils.Tile(t.tx, tile.ty); } // lat is on a y tile boundary, so we'll move it down if (t.ty < tile.ty) { tile = new TMSUtils.Tile(tile.tx, t.ty); } return tile; } return pixelsToTile(p.px, p.py, tilesize); }
@Test @Category(IntegrationTest.class) public void testGetOneWorker() throws Exception { // find a small enough tile bounds to 4 tiles TileBounds tb = new TileBounds(2764, 1365, 2765, 1366); Bounds bounds = TMSUtils.tileToBounds(tb, zoomLevel, tileSize); TiledInputFormatContext ifContext = new TiledInputFormatContext( zoomLevel, tileSize, new HashSet<String>(), bounds.convertNewToOldBounds(), new Properties()); ifContext.save(conf); int numWorkers = CostDistanceWorkersConfiguration.getNumWorkers(metadata, conf); Assert.assertEquals(1, numWorkers); }
@Test(expected = IllegalArgumentException.class) @Category(IntegrationTest.class) public void testMoreWorkersThanMapSlots() throws Exception { HadoopUtils.setupLocalRunner(conf); // find a large enough tile bounds TileBounds tb = new TileBounds(2764, 1365, 2878, 1479); Bounds bounds = TMSUtils.tileToBounds(tb, zoomLevel, tileSize); TiledInputFormatContext ifContext = new TiledInputFormatContext( zoomLevel, tileSize, new HashSet<String>(), bounds.convertNewToOldBounds(), new Properties()); ifContext.save(conf); CostDistanceWorkersConfiguration.getNumWorkers(metadata, conf); }
@Test @Category(IntegrationTest.class) public void testHardCodedWorkers() throws Exception { final int numExpectedWorkers = 5; MrGeoProperties.getInstance().setProperty("giraph.workers", String.valueOf(numExpectedWorkers)); // find a large enough tile bounds TileBounds tb = new TileBounds(2764, 1365, 2878, 1479); Bounds bounds = TMSUtils.tileToBounds(tb, zoomLevel, tileSize); TiledInputFormatContext ifContext = new TiledInputFormatContext( zoomLevel, tileSize, new HashSet<String>(), bounds.convertNewToOldBounds(), new Properties()); ifContext.save(conf); int numWorkers = CostDistanceWorkersConfiguration.getNumWorkers(metadata, conf); Assert.assertEquals(numExpectedWorkers, numWorkers); MrGeoProperties.getInstance().remove("giraph.workers"); }
// tests that numTiles is correctly computed - I had an off-by-one error due to assuming that // boundsToTile returns tile boundaries where the upper right is exclusive instead of inclusive @Test @Category(IntegrationTest.class) public void testNumTiles() throws Exception { conf.set("mapred.child.java.opts", "-Xmx2048M"); conf.setInt("io.sort.mb", 100); // find a large enough tile bounds TileBounds tb = new TileBounds(50, 100, 1000, 100); Bounds bounds = TMSUtils.tileToBounds(tb, zoomLevel, tileSize); TiledInputFormatContext ifContext = new TiledInputFormatContext( zoomLevel, tileSize, new HashSet<String>(), bounds.convertNewToOldBounds(), new Properties()); ifContext.save(conf); int numWorkers = CostDistanceWorkersConfiguration.getNumWorkers( metadata, conf, false /* disable map slots check */); Assert.assertEquals(4, numWorkers); }
// Converts lat/lon bounds to the correct tile bounds, in lat/lon for a zoom level public static Bounds tileBounds( final TMSUtils.Bounds bounds, final int zoom, final int tilesize) { final TMSUtils.TileBounds tb = TMSUtils.boundsToTile(bounds, zoom, tilesize); return TMSUtils.tileToBounds(tb, zoom, tilesize); }
public static Tile calculateTile( final Tile tile, final int srcZoom, final int dstZoom, final int tilesize) { final TMSUtils.Bounds bounds = TMSUtils.tileBounds(tile.tx, tile.ty, srcZoom, tilesize); return TMSUtils.latLonToTile(bounds.s, bounds.w, dstZoom, tilesize); }
/** * BoundsCropper takes an image (actually, its metadata), a list of user bounds to crop, and a * zoom level, and gives back the metadata corresponding to the cropped image with the maximum * zoom level set to the one provided. * * <p>Additional details: * * <p>If there is only one user bounds, then the cropped image bounds corresponds to that * singleton bounds. If there is a list of user bounds, then the cropped image bounds corresponds * to an envelope around the list of user bounds. * * <p>The new image bounds are computed from the old using the following two transformations - * first, the user bounds are capped to the nearest tile boundaries. - second, the bounds from * above are then intersected with the original image boundaries * * <p>The new tile bounds are computed from the new image bounds. * * <p>If the user bounds are outside the image bounds (i.e., they have no overlap), then an * exception is thrown * * <p>If the provided zoom level is different from the maximum zoom level in the input metadata, * then care is taken to set the maximum zoom level of the returned data to the provided zoom * level. * * @param origMetadata * @param userBounds * @param zoomLevel * @return */ public static MrsPyramidMetadata getCroppedMetadata( MrsPyramidMetadata origMetadata, List<Bounds> userBounds, int zoomLevel) { double minX = Double.POSITIVE_INFINITY, minY = Double.POSITIVE_INFINITY; double maxX = Double.NEGATIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY; // if there is a list of user bounds, find the envelope surrounding it for (Bounds bounds : userBounds) { if (bounds.w < minX) minX = bounds.w; if (bounds.s < minY) minY = bounds.s; if (bounds.e > maxX) maxX = bounds.e; if (bounds.n > maxY) maxY = bounds.n; } Bounds cropBounds = new Bounds(minX, minY, maxX, maxY); // now cap it to the nearest outside tile boundaries Bounds cropTileBounds = TMSUtils.tileBounds(cropBounds, zoomLevel, origMetadata.getTilesize()); // get the original image bounds Bounds imageBounds = Bounds.convertOldToNewBounds(origMetadata.getBounds()); // complain if the user bounds has no overlap with if (!imageBounds.intersect(cropTileBounds)) { throw new IllegalArgumentException( String.format( "Oops - cropped bounds and image bounds " + "do not overlap: cropped bounds=%s, image bounds=%s", cropTileBounds, imageBounds)); } // now find the intersection of the cropped bounds and image bounds - this becomes the new // image bounds Bounds newImageBounds = new Bounds( Math.max(cropTileBounds.w, imageBounds.w), Math.max(cropTileBounds.s, imageBounds.s), Math.min(cropTileBounds.e, imageBounds.e), Math.min(cropTileBounds.n, imageBounds.n)); // find the tile bounds corresponding to the new image bounds - this becomes the new tile bounds TMSUtils.TileBounds newTileBounds = TMSUtils.boundsToTile(newImageBounds, zoomLevel, origMetadata.getTilesize()); final TMSUtils.Pixel lowerPx = TMSUtils.latLonToPixels( newImageBounds.s, newImageBounds.w, zoomLevel, origMetadata.getTilesize()); final TMSUtils.Pixel upperPx = TMSUtils.latLonToPixels( newImageBounds.n, newImageBounds.e, zoomLevel, origMetadata.getTilesize()); final LongRectangle pixelBounds = new LongRectangle(0, 0, upperPx.px - lowerPx.px, upperPx.py - lowerPx.py); // time to create the new metadata MrsPyramidMetadata croppedMetadata = new MrsPyramidMetadata(); croppedMetadata.setPyramid(origMetadata.getPyramid()); croppedMetadata.setBounds(Bounds.convertNewToOldBounds(newImageBounds)); croppedMetadata.setTilesize(origMetadata.getTilesize()); croppedMetadata.setTileType(origMetadata.getTileType()); croppedMetadata.setBands(1); croppedMetadata.setDefaultValues(origMetadata.getDefaultValues()); // max zoom should be input zoom not origMetadata.getMaxZoomLevel croppedMetadata.setMaxZoomLevel(zoomLevel); croppedMetadata.setName(zoomLevel, "" + zoomLevel); croppedMetadata.setTileBounds(zoomLevel, TileBounds.convertToLongRectangle(newTileBounds)); croppedMetadata.setPixelBounds(zoomLevel, pixelBounds); croppedMetadata.setProtectionLevel(origMetadata.getProtectionLevel()); return croppedMetadata; }