/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2014, Open Source Geospatial Foundation (OSGeo)
*
* 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.spatialstatistics.operations;
import java.io.IOException;
import java.util.logging.Logger;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.process.spatialstatistics.core.DataUtils;
import org.geotools.process.spatialstatistics.core.FeatureTypes;
import org.geotools.process.spatialstatistics.enumeration.FishnetType;
import org.geotools.process.spatialstatistics.storage.IFeatureInserter;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
/**
* Creates a fishnet of rectangular cells.
*
* @author Minpa Lee, MangoSystem
*
* @source $URL$
*
*/
public class FishnetOperation extends GeneralOperation {
protected static final Logger LOGGER = Logging.getLogger(FishnetOperation.class);
static final String TYPE_NAME = "fishnet";
static final String UID = "uid";
private FishnetType fishnetType = FishnetType.Rectangle;
private SimpleFeatureCollection boundsSource = null;
private String the_geom = null;
private PreparedGeometry boundsGeometry = null;
private boolean boundaryInside = false;
public void setBoundaryInside(boolean boundaryInside) {
this.boundaryInside = boundaryInside;
}
public void setFishnetType(FishnetType fishnetType) {
this.fishnetType = fishnetType;
}
public void setGeometryBoundary(Geometry geometryBoundary) {
if (geometryBoundary == null) {
this.boundsGeometry = null;
} else {
this.boundsGeometry = PreparedGeometryFactory.prepare(geometryBoundary);
}
}
public void setBoundsSource(SimpleFeatureCollection boundsSource) {
this.boundsSource = boundsSource;
if (boundsSource == null) {
this.the_geom = null;
} else {
this.the_geom = boundsSource.getSchema().getGeometryDescriptor().getLocalName();
// use SpatialIndexFeatureCollection
this.boundsSource = DataUtils.toSpatialIndexFeatureCollection(boundsSource);
}
}
public SimpleFeatureCollection execute(ReferencedEnvelope bbox, Double width, Double height)
throws IOException {
int columns = (int) Math.floor((bbox.getWidth() / width) + 0.5d);
int rows = (int) Math.floor((bbox.getHeight() / height) + 0.5d);
columns = columns * width < bbox.getWidth() ? columns + 1 : columns;
rows = rows * height < bbox.getHeight() ? rows + 1 : rows;
// recalculate envelope : origin = lower left
final double x1 = bbox.getMinX();
final double y1 = bbox.getMinY();
final double x2 = bbox.getMinX() + (columns * width);
final double y2 = bbox.getMinY() + (rows * height);
CoordinateReferenceSystem crs = bbox.getCoordinateReferenceSystem();
ReferencedEnvelope finalBBox = new ReferencedEnvelope(crs);
finalBBox.init(x1, x2, y1, y2);
return execute(finalBBox, columns, rows);
}
public SimpleFeatureCollection execute(ReferencedEnvelope bbox, Integer columns, Integer rows)
throws IOException {
CoordinateReferenceSystem crs = bbox.getCoordinateReferenceSystem();
SimpleFeatureType schema = FeatureTypes.getDefaultType(TYPE_NAME, Polygon.class, crs);
schema = FeatureTypes.add(schema, UID, Integer.class, 19);
final double width = bbox.getWidth() / columns;
final double height = bbox.getHeight() / rows;
final double minX = bbox.getMinX();
final double minY = bbox.getMinY();
// insert features
IFeatureInserter featureWriter = getFeatureWriter(schema);
try {
int featureID = 0;
ReferencedEnvelope bounds = new ReferencedEnvelope(crs);
double ypos = minY;
for (int row = 0; row < rows; row++) {
double xpos = minX;
for (int col = 0; col < columns; col++) {
bounds.init(xpos, xpos + width, ypos, ypos + height);
Geometry cellGeom = null;
switch (fishnetType) {
case Rectangle:
cellGeom = gf.toGeometry(bounds);
break;
case Circle:
double radius = bounds.getWidth() / 2.0;
cellGeom = gf.createPoint(bounds.centre()).buffer(radius);
break;
}
if (boundsGeometry != null) {
if (boundaryInside) {
if (!boundsGeometry.contains(cellGeom)) {
xpos += width;
continue;
}
} else {
if (!boundsGeometry.intersects(cellGeom)) {
xpos += width;
continue;
}
}
}
if (boundsSource != null) {
Filter filter = getIntersectsFilter(the_geom, cellGeom);
if (boundaryInside) {
filter = ff.within(ff.property(the_geom), ff.literal(cellGeom));
}
if (boundsSource.subCollection(filter).isEmpty()) {
xpos += width;
continue;
}
}
// create feature and set geometry
SimpleFeature newFeature = featureWriter.buildFeature();
newFeature.setAttribute(UID, featureID);
newFeature.setDefaultGeometry(cellGeom);
featureWriter.write(newFeature);
xpos += width;
}
ypos += height;
}
} catch (Exception e) {
featureWriter.rollback(e);
} finally {
featureWriter.close();
}
return featureWriter.getFeatureCollection();
}
}