package com.revolsys.gis.grid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.revolsys.collection.map.MapEx;
import com.revolsys.geometry.cs.CoordinateSystem;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.Point;
import com.revolsys.io.map.MapObjectFactory;
import com.revolsys.util.MathUtil;
public class CustomRectangularMapGrid extends AbstractRectangularMapGrid {
private static final double DEFAULT_TILE_SIZE = 1000;
public static int getGridCeil(final double origin, final double gridSize, final double value) {
final int xIndex = (int)Math.ceil((value - origin) / gridSize);
final double gridValue = origin + xIndex * gridSize;
return (int)gridValue;
}
public static int getGridFloor(final double origin, final double gridSize, final double value) {
final int xIndex = (int)Math.floor((value - origin) / gridSize);
final double gridValue = origin + xIndex * gridSize;
return (int)gridValue;
}
private GeometryFactory geometryFactory = GeometryFactory.DEFAULT_3D;
private double originX = 0.0;
private double originY = 0.0;
private double tileHeight = DEFAULT_TILE_SIZE;
private double tileWidth = DEFAULT_TILE_SIZE;
public CustomRectangularMapGrid() {
}
public CustomRectangularMapGrid(final GeometryFactory geometryFactory) {
this(geometryFactory, 0, 0, DEFAULT_TILE_SIZE, DEFAULT_TILE_SIZE);
}
public CustomRectangularMapGrid(final GeometryFactory geometryFactory, final double tileSize) {
this(geometryFactory, 0, 0, tileSize, tileSize);
}
public CustomRectangularMapGrid(final GeometryFactory geometryFactory, final double tileWidth,
final double tileHeight) {
this(geometryFactory, 0, 0, tileWidth, tileHeight);
}
public CustomRectangularMapGrid(final GeometryFactory geometryFactory, final double originX,
final double originY, final double tileWidth, final double tileHeight) {
this.geometryFactory = geometryFactory;
this.tileHeight = tileHeight;
this.tileWidth = tileWidth;
this.originX = originX;
this.originY = originY;
}
public CustomRectangularMapGrid(final Map<String, ? extends Object> properties) {
setProperties(properties);
}
public List<RectangularMapTile> getAllTiles(final BoundingBox boundingBox) {
final BoundingBox envelope = boundingBox.convert(getGeometryFactory());
final List<RectangularMapTile> tiles = new ArrayList<>();
final int minX = getGridFloor(this.originX, this.tileWidth, envelope.getMinX());
final int minY = getGridFloor(this.originY, this.tileHeight, envelope.getMinY());
final int maxX = getGridCeil(this.originX, this.tileWidth, envelope.getMaxX());
final int maxY = getGridCeil(this.originY, this.tileHeight, envelope.getMaxY());
final int numX = (int)Math.ceil((maxX - minX) / this.tileWidth);
final int numY = (int)Math.ceil((maxY - minY) / this.tileWidth);
for (int i = 0; i < numY; i++) {
final double y = minY + i * this.tileHeight;
for (int j = 0; j < numX; j++) {
final double x = minX + j * this.tileWidth;
final RectangularMapTile tile = getTileByLocation(x, y);
tiles.add(tile);
}
}
return tiles;
}
public BoundingBox getBoundingBox(final String name) {
final double[] coordinates = MathUtil.toDoubleArraySplit(name, "_");
if (coordinates.length == 2) {
final double x1 = coordinates[0];
final double y1 = coordinates[1];
final double x2 = x1 + this.tileWidth;
final double y2 = y1 + this.tileHeight;
return this.geometryFactory.newBoundingBox(x1, y1, x2, y2);
} else {
return null;
}
}
@Override
public CoordinateSystem getCoordinateSystem() {
return this.geometryFactory.getCoordinateSystem();
}
@Override
public String getFormattedMapTileName(final String name) {
return name;
}
@Override
public GeometryFactory getGeometryFactory() {
return this.geometryFactory;
}
@Override
public String getMapTileName(final double x, final double y) {
final int tileX = getTileX(x);
final int tileY = getTileY(y);
return tileX + "_" + tileY;
}
public String getMapTileName(final Point coordinates) {
final double x = coordinates.getX();
final double y = coordinates.getY();
return getMapTileName(x, y);
}
public double getOriginX() {
return this.originX;
}
public double getOriginY() {
return this.originY;
}
@Override
public RectangularMapTile getTileByLocation(final double x, final double y) {
final String name = getMapTileName(x, y);
if (name == null) {
return null;
} else {
return getTileByName(name);
}
}
@Override
public RectangularMapTile getTileByName(final String name) {
final BoundingBox boundingBox = getBoundingBox(name);
if (boundingBox == null) {
return null;
} else {
return new SimpleRectangularMapTile(this, name, name, boundingBox);
}
}
@Override
public double getTileHeight() {
return this.tileHeight;
}
@Override
public List<RectangularMapTile> getTiles(final BoundingBox boundingBox) {
final BoundingBox envelope = boundingBox.convert(getGeometryFactory());
final List<RectangularMapTile> tiles = new ArrayList<>();
final int minX = getGridFloor(this.originX, this.tileWidth, envelope.getMinX());
final int minY = getGridFloor(this.originY, this.tileHeight, envelope.getMinY());
final int maxX = getGridCeil(this.originX, this.tileWidth, envelope.getMaxX());
final int maxY = getGridCeil(this.originY, this.tileHeight, envelope.getMaxY());
final int numX = (int)Math.ceil((maxX - minX) / this.tileWidth);
final int numY = (int)Math.ceil((maxY - minY) / this.tileWidth);
if (numX > 40 || numY > 40) {
return tiles;
}
for (int i = 0; i < numY; i++) {
final double y = minY + i * this.tileHeight;
for (int j = 0; j < numX; j++) {
final double x = minX + j * this.tileWidth;
final RectangularMapTile tile = getTileByLocation(x, y);
tiles.add(tile);
}
}
return tiles;
}
@Override
public double getTileWidth() {
return this.tileWidth;
}
public int getTileX(final double x) {
return getGridFloor(this.originX, this.tileWidth, x);
}
public int getTileY(final double y) {
return getGridFloor(this.originY, this.tileHeight, y);
}
public void setGeometryFactory(final GeometryFactory geometryFactory) {
this.geometryFactory = geometryFactory;
}
public void setOriginX(final double originX) {
this.originX = originX;
}
public void setOriginY(final double originY) {
this.originY = originY;
}
public void setSrid(final int srid) {
setGeometryFactory(GeometryFactory.fixed(srid, 1.0, 1.0));
}
public void setTileHeight(final double tileHeight) {
this.tileHeight = tileHeight;
}
public void setTileSize(final double tileSize) {
setTileWidth(tileSize);
setTileHeight(tileSize);
}
public void setTileWidth(final double tileWidth) {
this.tileWidth = tileWidth;
}
@Override
public MapEx toMap() {
final MapEx map = super.toMap();
map.put(MapObjectFactory.TYPE, "customRectangularMapGrid");
addToMap(map, "geometryFactory", getGeometryFactory());
addToMap(map, "originX", getOriginX());
addToMap(map, "originY", getOriginY());
addToMap(map, "tileWidth", getTileWidth());
addToMap(map, "tileHeight", getTileHeight());
return map;
}
@Override
public String toString() {
final StringBuilder string = new StringBuilder();
if (this.geometryFactory != null) {
string.append(this.geometryFactory.getCoordinateSystem().getCoordinateSystemName());
string.append(" ");
}
if (this.originX != 0 && this.originY != 0) {
string.append(this.originX);
string.append(',');
string.append(this.originY);
}
string.append(this.tileWidth);
string.append('x');
string.append(this.tileHeight);
return string.toString();
}
}