
org.geolatte.mapserver.tms.BoundingBoxOp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of geolatte-mapserver Show documentation
Show all versions of geolatte-mapserver Show documentation
An embeddable map server supporting the WMS, WMTS and TMS protocols
The newest version!
/*
* Copyright 2009-2010 Geovise BVBA, QMINO BVBA
*
* This file is part of GeoLatte Mapserver.
*
* GeoLatte Mapserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GeoLatte Mapserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GeoLatte Mapserver. If not, see .
*/
package org.geolatte.mapserver.tms;
import org.apache.log4j.Logger;
import org.geolatte.geom.Envelope;
import org.geolatte.mapserver.img.Imaging;
import org.geolatte.mapserver.util.Chrono;
import org.geolatte.mapserver.util.PixelRange;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.util.HashSet;
import java.util.Set;
/**
* Creates the image from a TileMap
that best fits a BoundingBox
.
*
* This operation proceeds as follows:
* - the requested map units per pixel (upp) are calculated from the specified bounding box and image dimensions
* - the
TileSet
of the specified TileMap
is determined whose upp is closest to the requested upp
* - the
Tile
s are determined that overlap the requested BoundingBox
in this TileSet
* - the images for these
Tile
s are retrieved (from disc or a network connection)
* - the images are mosaiced to a single image and cropped on the requested bounding box
* - the result is rescaled to fit in the requested bounding box
*
*
*
*
* @author Karel Maesen, Geovise BVBA
*/
public class BoundingBoxOp implements TileMapOperation {
private final static Logger LOGGER = Logger.getLogger(BoundingBoxOp.class);
final private Envelope requestedBbox;
final private Dimension dimension;
private final Imaging imaging;
final private TileMap tileMap;
private Envelope tileSetClippedBbox;
private TileSet tileSet;
private Set tiles;
private Set images = new HashSet();
private TileImage result;
private Chrono chrono;
private PixelRange imgBounds;
/**
* Constructs this operation
* @param tileMap the TileMap
on which to operate
* @param boundingBox the BoundingBox
for the result
* @param dimension the image dimensions of the result
* @param imaging the Imaging
instance to use for the image-manipulation
*/
public BoundingBoxOp(TileMap tileMap, Envelope boundingBox, Dimension dimension, Imaging imaging) {
this.tileMap = tileMap;
this.dimension = dimension;
this.requestedBbox = boundingBox;
this.imaging = imaging;
this.tileSetClippedBbox = this.tileMap.clipToMaxBoundingBox(boundingBox);
}
/**
* Executes this operation
* @return the TileImage
showing the part of the tile map within the bounding box and having
* the specified image dimensions.
*/
@Override
public TileImage execute() {
if (tileSetClippedBbox.isEmpty() || tileSetClippedBbox.getWidth() < 1 || tileSetClippedBbox.getHeight() < 1) {
return imaging.createEmptyImage(this.dimension, this.tileMap.getTileImageFormat());
}
chrono = new Chrono();
chooseTileSet();
getTiles();
if (tiles.isEmpty()) return imaging.createEmptyImage(dimension, this.tileMap.getTileImageFormat());
chrono.reset();
loadTileImages();
mosaic();
crop();
scale();
LOGGER.debug("Image processing took " + chrono.stop() + " ms.");
LOGGER.debug("Total execution is: " + chrono.total() + " ms.");
return result;
}
private void chooseTileSet() {
TileSetChooser tsc = new TileSetChooser(tileMap, requestedBbox, dimension);
tileSet = tsc.chooseTileSet();
LOGGER.debug("TileSet chosen has order = " + tileSet.getOrder());
}
private void getTiles() {
tiles = tileMap.getTilesFor(tileSet, tileSetClippedBbox);
}
protected void loadTileImages() {
TileImageLoadOp loadOp = new TileImageLoadOp(this.tiles, this.imaging, tileMap.isForceArgb());
images = loadOp.execute();
LOGGER.debug("Image loading took " + chrono.stop() + " ms.");
}
private void mosaic() {
imgBounds = Tile.pixelBounds(tiles);
result = imaging.mosaic(images, imgBounds);
}
private void crop() {
PixelRange cropBnds = tileSet.pixelBounds(tileSetClippedBbox);
result = imaging.crop(result, cropBnds);
}
private void scale() {
if (!tileSetClippedBbox.equals(requestedBbox)) {
//if the request bbox is extends beyond the
// bbox of the TileSet, then we must embed
// the result in a larger, empty image
embedInEmptyImage();
} else {
result = imaging.scale(result, dimension);
}
}
private void embedInEmptyImage() {
TileImage empty = createEmptyBackgroundImage();
applyEmbeddingTransform();
result = imaging.overlay(empty, result);
}
private void applyEmbeddingTransform() {
AffineTransform atf = createEmbeddingTransform();
result = imaging.affineTransform(result, atf);
}
private AffineTransform createEmbeddingTransform() {
MapUnitToPixelTransform mupTransform = new MapUnitToPixelTransform(requestedBbox, new PixelRange(0, 0, (int) dimension.getWidth(), (int) dimension.getHeight()));
PixelRange destRange = mupTransform.toPixelRange(tileSetClippedBbox);
double m00 = (double) destRange.getWidth() / (double) result.getWidth();
double m02 = destRange.getMinX() - result.getMinX() * m00;
double m11 = (double) destRange.getHeight() / (double) result.getHeight();
double m12 = destRange.getMinY() - result.getMinY() * m11;
AffineTransform atf = new AffineTransform(m00, 0.0, 0.0, m11, m02, m12);
return atf;
}
private TileImage createEmptyBackgroundImage() {
TileImage empty = imaging.createEmptyImage(result, dimension);
return empty;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy