/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.gears.modules.v.grids;
import static org.jgrasstools.gears.libs.modules.JGTConstants.VECTORPROCESSING;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.Documentation;
import oms3.annotations.Execute;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Out;
import oms3.annotations.Status;
import oms3.annotations.UI;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.grid.DefaultGridFeatureBuilder;
import org.geotools.grid.GridFeatureBuilder;
import org.geotools.grid.Grids;
import org.geotools.grid.Lines;
import org.geotools.grid.oblong.Oblongs;
import org.geotools.grid.ortholine.LineOrientation;
import org.geotools.grid.ortholine.OrthoLineDef;
import org.geotools.referencing.CRS;
import org.jgrasstools.gears.libs.exceptions.ModelsIllegalargumentException;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.gears.utils.CrsUtilities;
import org.jgrasstools.gears.utils.features.FeatureUtilities;
import org.jgrasstools.gears.utils.geometry.GeometryUtilities;
import org.jgrasstools.gears.utils.math.NumericsUtilities;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
@Description(OmsGridsGenerator.OMSGRIDSGENERATOR_DESCRIPTION)
@Documentation(OmsGridsGenerator.OMSGRIDSGENERATOR_DOCUMENTATION)
@Author(name = OmsGridsGenerator.OMSGRIDSGENERATOR_AUTHORNAMES, contact = OmsGridsGenerator.OMSGRIDSGENERATOR_AUTHORCONTACTS)
@Keywords(OmsGridsGenerator.OMSGRIDSGENERATOR_KEYWORDS)
@Label(OmsGridsGenerator.OMSGRIDSGENERATOR_LABEL)
@Name(OmsGridsGenerator.OMSGRIDSGENERATOR_NAME)
@Status(OmsGridsGenerator.OMSGRIDSGENERATOR_STATUS)
@License(OmsGridsGenerator.OMSGRIDSGENERATOR_LICENSE)
public class OmsGridsGenerator extends JGTModel {
@Description(OMSGRIDSGENERATOR_inVector_DESCRIPTION)
@In
public SimpleFeatureCollection inVector = null;
@Description(OMSGRIDSGENERATOR_inRaster_DESCRIPTION)
@In
public GridCoverage2D inRaster = null;
@Description(OMSGRIDSGENERATOR_pLon_DESCRIPTION)
@In
public Double pLon;
@Description(OMSGRIDSGENERATOR_pLat_DESCRIPTION)
@In
public Double pLat;
@Description(OMSGRIDSGENERATOR_pWidth_DESCRIPTION)
@In
public Double pWidth;
@Description(OMSGRIDSGENERATOR_pHeight_DESCRIPTION)
@In
public Double pHeight;
@Description(OMSGRIDSGENERATOR_pRows_DESCRIPTION)
@In
public int pRows = 10;
@Description(OMSGRIDSGENERATOR_pCols_DESCRIPTION)
@In
public int pCols = 10;
@Description(OMSGRIDSGENERATOR_pSpacing_DESCRIPTION)
@In
public Double pSpacing = null;
@Description(OMSGRIDSGENERATOR_pType_DESCRIPTION)
@UI("combo: " + POLYGON + "," + LINE + "," + POINT)
@In
public String pType = POLYGON;
@Description(OMSGRIDSGENERATOR_pCode_DESCRIPTION)
@UI(JGTConstants.CRS_UI_HINT)
@In
public String pCode;
@Description(OMSGRIDSGENERATOR_outMap_DESCRIPTION)
@Out
public SimpleFeatureCollection outMap = null;
public static final String POINT = "point";
public static final String LINE = "line";
public static final String POLYGON = "polygon";
// VARS DOCS START
public static final String OMSGRIDSGENERATOR_DESCRIPTION = "Generates grid of lines or polygons.";
public static final String OMSGRIDSGENERATOR_DOCUMENTATION = "";
public static final String OMSGRIDSGENERATOR_KEYWORDS = "Vector, Grid";
public static final String OMSGRIDSGENERATOR_LABEL = VECTORPROCESSING;
public static final String OMSGRIDSGENERATOR_NAME = "gridgenerator";
public static final int OMSGRIDSGENERATOR_STATUS = 40;
public static final String OMSGRIDSGENERATOR_LICENSE = "http://www.gnu.org/licenses/gpl-3.0.html";
public static final String OMSGRIDSGENERATOR_AUTHORNAMES = "Andrea Antonello";
public static final String OMSGRIDSGENERATOR_AUTHORCONTACTS = "http://www.hydrologis.com";
public static final String OMSGRIDSGENERATOR_inVector_DESCRIPTION = "Optional vector map from which to take the bounds (if supplied, all other bounds related parameter are ignored). This needs pRows and pCols to be defined.";
public static final String OMSGRIDSGENERATOR_inRaster_DESCRIPTION = "Optional raster map from which to take the bounds (if supplied, all other bounds related parameter are ignored. This needs pRows and pCols to be defined.";
public static final String OMSGRIDSGENERATOR_pLon_DESCRIPTION = "The lower left longitude (needed if no map is supplied).";
public static final String OMSGRIDSGENERATOR_pLat_DESCRIPTION = "The lower left latitude (needed if no map is supplied).";
public static final String OMSGRIDSGENERATOR_pWidth_DESCRIPTION = "The optional grid cell width.";
public static final String OMSGRIDSGENERATOR_pHeight_DESCRIPTION = "The optional grid cell height.";
public static final String OMSGRIDSGENERATOR_pRows_DESCRIPTION = "The number of rows.";
public static final String OMSGRIDSGENERATOR_pCols_DESCRIPTION = "The number of cols.";
public static final String OMSGRIDSGENERATOR_pSpacing_DESCRIPTION = "The vertex spacing to use.";
public static final String OMSGRIDSGENERATOR_pType_DESCRIPTION = "The output type.";
public static final String OMSGRIDSGENERATOR_pCode_DESCRIPTION = "The code defining the coordinate reference system, composed by authority and code number (ex. EPSG:4328). Applied in the case the file is missing.";
public static final String OMSGRIDSGENERATOR_outMap_DESCRIPTION = "The grid.";
// VARS DOC END
@Execute
public void process() throws Exception {
boolean isSquare;
double s;
double n;
double w;
double e;
CoordinateReferenceSystem crs;
if (inVector != null) {
ReferencedEnvelope bounds = inVector.getBounds();
crs = inVector.getSchema().getCoordinateReferenceSystem();
s = bounds.getMinY();
n = bounds.getMaxY();
w = bounds.getMinX();
e = bounds.getMaxX();
pWidth = bounds.getWidth() / pCols;
pHeight = bounds.getHeight() / pRows;
} else if (inRaster != null) {
Envelope2D bounds = inRaster.getGridGeometry().getEnvelope2D();
crs = inRaster.getCoordinateReferenceSystem();
s = bounds.getMinY();
w = bounds.getMinX();
if (pWidth != null && pHeight != null) {
n = s + pWidth * pCols;
e = w + pHeight * pRows;
} else {
n = bounds.getMaxY();
e = bounds.getMaxX();
pWidth = bounds.getWidth() / pCols;
pHeight = bounds.getHeight() / pRows;
}
} else {
checkNull(pCode, pLat, pLon);
s = pLat;
n = pLat + pRows * pHeight;
w = pLon;
e = pLon + pCols * pWidth;
crs = CrsUtilities.getCrsFromEpsg(pCode, null);
}
isSquare = NumericsUtilities.dEq(pWidth, pHeight) ? true : false;
outMap = new DefaultFeatureCollection();
double delta = 0.000001;
ReferencedEnvelope env = new ReferencedEnvelope(w, e + delta, s, n + delta, crs);
pm.beginTask("Generating grid...", IJGTProgressMonitor.UNKNOWN);
GridFeatureBuilder builder = new DefaultGridFeatureBuilder(crs);
SimpleFeatureSource grid;
switch( pType ) {
case POLYGON:
if (isSquare) {
if (pSpacing != null) {
grid = Grids.createSquareGrid(env, pWidth, pSpacing);
} else {
grid = Grids.createSquareGrid(env, pWidth);
}
} else {
if (pSpacing != null) {
grid = Oblongs.createGrid(env, pWidth, pHeight, pSpacing, builder);
} else {
grid = Oblongs.createGrid(env, pWidth, pHeight, builder);
}
}
outMap = grid.getFeatures();
List<Geometry> geomsList = FeatureUtilities.featureCollectionToGeometriesList(outMap, true, null);
createPolygons(crs, gf, geomsList);
break;
case LINE:
case POINT:
List<OrthoLineDef> lineDefs = Arrays.asList(//
new OrthoLineDef(LineOrientation.VERTICAL, 1, pHeight), //
new OrthoLineDef(LineOrientation.HORIZONTAL, 1, pWidth) //
);
if (pSpacing != null) {
grid = Lines.createOrthoLines(env, lineDefs, pSpacing, builder);
} else {
grid = Lines.createOrthoLines(env, lineDefs);
}
outMap = grid.getFeatures();
GeometryFactory gf = GeometryUtilities.gf();
List<Geometry> geoms = FeatureUtilities.featureCollectionToGeometriesList(outMap, true, null);
List<LineString> verticals = new ArrayList<LineString>();
List<LineString> horizontals = new ArrayList<LineString>();
for( Geometry geometry : geoms ) {
Envelope envelope = geometry.getEnvelopeInternal();
Coordinate first = new Coordinate(envelope.getMinX(), envelope.getMinY());
Coordinate last = new Coordinate(envelope.getMaxX(), envelope.getMaxY());
LineString lineString = gf.createLineString(new Coordinate[]{first, last});
if (envelope.getWidth() > envelope.getHeight()) {
horizontals.add(lineString);
} else {
verticals.add(lineString);
}
}
if (pType.equals(LINE)) {
createLines(crs, verticals, horizontals);
} else {
createPoints(crs, gf, verticals, horizontals);
}
break;
default:
throw new ModelsIllegalargumentException("The supplied pType is not supported.", this, pm);
}
pm.done();
}
private void createPolygons( CoordinateReferenceSystem crs, GeometryFactory gf, List<Geometry> polygons ) {
outMap = new DefaultFeatureCollection();
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName(POLYGON);
b.setCRS(crs);
b.add("the_geom", Polygon.class);
b.add("id", Long.class);
SimpleFeatureType type = b.buildFeatureType();
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
long index = 0;
int numGeometries = polygons.size();
for( int i = 0; i < numGeometries; i++ ) {
Geometry geometry = polygons.get(i);
Object[] values = new Object[]{geometry, index++};
fbuilder.addAll(values);
SimpleFeature feature = fbuilder.buildFeature(null);
((DefaultFeatureCollection) outMap).add(feature);
}
}
private void createPoints( CoordinateReferenceSystem crs, GeometryFactory gf, List<LineString> verticals,
List<LineString> horizontals ) {
outMap = new DefaultFeatureCollection();
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName(POINT);
b.setCRS(crs);
b.add("the_geom", Point.class);
b.add("id", Long.class);
SimpleFeatureType type = b.buildFeatureType();
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
Geometry gVer = gf.createMultiLineString(verticals.toArray(new LineString[0]));
Geometry gHor = gf.createMultiLineString(horizontals.toArray(new LineString[0]));
Geometry intersection = gHor.intersection(gVer);
long index = 0;
int numGeometries = intersection.getNumGeometries();
for( int i = 0; i < numGeometries; i++ ) {
Geometry geometry = intersection.getGeometryN(i);
Object[] values = new Object[]{geometry, index++};
fbuilder.addAll(values);
SimpleFeature feature = fbuilder.buildFeature(null);
((DefaultFeatureCollection) outMap).add(feature);
}
}
private void createLines( CoordinateReferenceSystem crs, List<LineString> verticals, List<LineString> horizontals ) {
outMap = new DefaultFeatureCollection();
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName(LINE);
b.setCRS(crs);
b.add("the_geom", MultiLineString.class);
b.add("id", Long.class);
SimpleFeatureType type = b.buildFeatureType();
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
long index = 0;
for( LineString lineString : horizontals ) {
Object[] values = new Object[]{lineString, index++};
fbuilder.addAll(values);
SimpleFeature feature = fbuilder.buildFeature(null);
((DefaultFeatureCollection) outMap).add(feature);
}
for( LineString lineString : verticals ) {
Object[] values = new Object[]{lineString, index++};
fbuilder.addAll(values);
SimpleFeature feature = fbuilder.buildFeature(null);
((DefaultFeatureCollection) outMap).add(feature);
}
}
}