/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2011, Open Source Geospatial Foundation (OSGeo)
* (C) 2008-2011 TOPP - www.openplans.org.
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotools.process.feature.gs;
import java.io.IOException;
import java.util.Map;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.grid.GridElement;
import org.geotools.grid.GridFeatureBuilder;
import org.geotools.grid.PolygonElement;
import org.geotools.grid.hexagon.HexagonOrientation;
import org.geotools.grid.hexagon.Hexagons;
import org.geotools.grid.oblong.Oblongs;
import org.geotools.process.ProcessException;
import org.geotools.process.factory.DescribeParameter;
import org.geotools.process.factory.DescribeProcess;
import org.geotools.process.factory.DescribeResult;
import org.geotools.process.gs.GSProcess;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Polygon;
/**
* A process that builds a regular grid as a feature collection
*
* @author Andrea Aime - GeoSolutions
*
* @source $URL$
*/
@DescribeProcess(title = "grid", description = "Builds a regular cell grid")
public class GridProcess implements GSProcess {
enum GridMode {
Rectangular, HexagonFlat, HexagonAngled
};
@DescribeResult(name = "result", description = "The grid")
public SimpleFeatureCollection execute(
@DescribeParameter(name = "features", description = "The grid bounds") ReferencedEnvelope bounds,
@DescribeParameter(name = "width", description = "Cell width (in the same uom as the bounds referencing system)") double width,
@DescribeParameter(name = "height", description = "Cell height (optional, used only for rectangular grids, "
+ "if not provided it is assumed equals to the width)", min = 0) Double height,
@DescribeParameter(name = "vertexSpacing", description = "Distance between vertices (used to create densified " +
"sides suitable for reprojection)", min = 0) Double vertexSpacing,
@DescribeParameter(name = "mode", description = "The type of grid to be generated", min = 0) GridMode mode)
throws ProcessException {
final GridFeatureBuilder builder = new GridFeatureBuilderImpl(bounds
.getCoordinateReferenceSystem());
double h = height != null ? height : width;
SimpleFeatureSource source;
if (mode == null || mode == GridMode.Rectangular) {
source = Oblongs.createGrid(bounds, width, h, builder);
} else if (mode == GridMode.HexagonFlat) {
source = Hexagons.createGrid(bounds, width, HexagonOrientation.FLAT, builder);
} else {
source = Hexagons.createGrid(bounds, width, HexagonOrientation.ANGLED, builder);
}
try {
return source.getFeatures();
} catch (IOException e) {
throw new ProcessException("Unexpected exception while grabbing features", e);
}
}
/**
* Builds the feature attributes providing the cell center and a stable id
*
* @author Andrea Aime - GeoSolutions
*/
static final class GridFeatureBuilderImpl extends GridFeatureBuilder {
private int id;
/**
* Creates the feature TYPE
*
* @param typeName
* name for the feature TYPE; if {@code null} or empty,
* {@linkplain #DEFAULT_TYPE_NAME} will be used
*
* @param crs
* coordinate reference system (may be {@code null})
*
* @return the feature TYPE
*/
protected static SimpleFeatureType createType(CoordinateReferenceSystem crs) {
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
tb.setName("grid");
tb.add("cell", Polygon.class, crs);
tb.add("id", Integer.class);
tb.add("centerX", Double.class);
tb.add("centerY", Double.class);
return tb.buildFeatureType();
}
/**
* Creates a new instance.
*
* @param crs
* coordinate reference system (may be {@code null})
*/
public GridFeatureBuilderImpl(CoordinateReferenceSystem crs) {
super(createType(crs));
}
@Override
public String getFeatureID(GridElement ge) {
return String.valueOf("grid." + (id++));
}
/**
* Overrides {@linkplain GridFeatureBuilder#setAttributes(GridElement, Map)} to assign a
* sequential integer id value to each grid element feature as it is constructed.
*
* @param el
* the element from which the new feature is being constructed
*
* @param attributes
* a {@code Map} with the single key "id"
*/
@Override
public void setAttributes(GridElement ge, Map<String, Object> attributes) {
PolygonElement pe = (PolygonElement) ge;
attributes.put("id", id);
attributes.put("centerX", pe.getCenter().x);
attributes.put("centerY", pe.getCenter().y);
}
}
}