package org.geowebcache.arcgis.layer;
import java.util.List;
import org.geowebcache.arcgis.config.CacheInfo;
import org.geowebcache.arcgis.config.LODInfo;
import org.geowebcache.arcgis.config.SpatialReference;
import org.geowebcache.arcgis.config.TileCacheInfo;
import org.geowebcache.arcgis.config.TileOrigin;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.GridSet;
import org.geowebcache.grid.GridSetFactory;
import org.geowebcache.grid.SRS;
import org.springframework.util.Assert;
/**
* Utility to crate a {@link GridSet} out of a ArcGIS tiling scheme
*
* @author Gabriel Roldan
*
*/
class GridSetBuilder {
/**
* Creates a {@link GridSet} out of a ArcGIS tiling scheme
*
* @param layerName
* @param info
* @param layerBounds
* @return
*/
public GridSet buildGridset(final String layerName, final CacheInfo info,
final BoundingBox layerBounds) {
Assert.notNull(layerName);
Assert.notNull(info);
Assert.notNull(layerBounds);
final TileCacheInfo tileCacheInfo = info.getTileCacheInfo();
final SpatialReference spatialReference = tileCacheInfo.getSpatialReference();
final SRS srs;
final BoundingBox gridSetExtent;
final boolean alignTopLeft = true;
final double[] resolutions;
/*
* let scale denoms be null so GridSetFactory computes them based on resolutions. The
* resulting values will be pretty close to the ones defined in the ArcGIS tiling scheme
*/
final double[] scaleDenominators = null;
final Double metersPerUnit;
final String[] scaleNames = null;
final int tileWidth = tileCacheInfo.getTileCols();
final int tileHeight = tileCacheInfo.getTileRows();
final boolean yCoordinateFirst = false;
final double pixelSize = 0.0254 / tileCacheInfo.getDPI();// see GridSubset.getDotsPerInch()
{
int epsgNumber = spatialReference.getWKID();
if (0 == epsgNumber) {
}
srs = SRS.getSRS(epsgNumber);
}
{
final List<LODInfo> lodInfos = tileCacheInfo.getLodInfos();
double[][] resAndScales = getResolutions(lodInfos);
resolutions = resAndScales[0];
double[] scales = resAndScales[1];
metersPerUnit = (0.00028 * scales[0]) / resolutions[0];
}
{
// See "How to calculate the -x parameter used in the examples above" at
// http://resources.arcgis.com/content/kbase?q=content/kbase&fa=articleShow&d=15558&print=true
// double XOrigin = spatialReference.getXOrigin();
// double YOrigin = spatialReference.getYOrigin();
// XYScale = 40075017 / 360 = ~111319, where 40075017 is the circumference of the earth
// at the ecuator and 360 the map units at the ecuator
// final double xyScale = spatialReference.getXYScale();
final TileOrigin tileOrigin = tileCacheInfo.getTileOrigin();// top left coordinate
double xmin = tileOrigin.getX();
double ymax = tileOrigin.getY();
double ymin = layerBounds.getMinY();
double xmax = layerBounds.getMaxX();
// make it so the gridset height matches an integer number of tiles in order for
// clients (OpenLayers) assuming the tile origin is the lower left corner instead of
// the upper right to compute tile bounding boxes right
final double resolution = resolutions[resolutions.length - 1];
double width = resolution * tileWidth;
double height = resolution * tileHeight;
long numTilesWide = (long) Math.ceil((xmax - xmin) / width);
long numTilesHigh = (long) Math.ceil((ymax - ymin) / height);
xmax = xmin + (numTilesWide * width);
ymin = ymax - (numTilesHigh * height);
gridSetExtent = new BoundingBox(xmin, ymin, xmax, ymax);
}
String gridsetName = srs.toString() + "_" + layerName;
GridSet layerGridset = GridSetFactory.createGridSet(gridsetName, srs, gridSetExtent,
alignTopLeft, resolutions, scaleDenominators, metersPerUnit, pixelSize, scaleNames,
tileWidth, tileHeight, yCoordinateFirst);
return layerGridset;
}
private double[][] getResolutions(List<LODInfo> lodInfos) {
final int numLevelsOfDetail = lodInfos.size();
double[][] resolutionsAndScales = new double[2][numLevelsOfDetail];
LODInfo lodInfo;
for (int i = 0; i < numLevelsOfDetail; i++) {
lodInfo = lodInfos.get(i);
resolutionsAndScales[0][i] = lodInfo.getResolution();
resolutionsAndScales[1][i] = lodInfo.getScale();
}
return resolutionsAndScales;
}
}