001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006-2007, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.resources.coverage;
017:
018: import java.awt.geom.Point2D;
019: import java.awt.geom.Rectangle2D;
020: import java.util.List;
021:
022: import org.geotools.coverage.grid.GridCoverage2D;
023: import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
024: import org.geotools.factory.FactoryConfigurationError;
025: import org.geotools.feature.AttributeType;
026: import org.geotools.feature.AttributeTypeFactory;
027: import org.geotools.feature.DefaultFeatureType;
028: import org.geotools.feature.Feature;
029: import org.geotools.feature.FeatureCollection;
030: import org.geotools.feature.FeatureCollections;
031: import org.geotools.feature.FeatureTypeBuilder;
032: import org.geotools.feature.IllegalAttributeException;
033: import org.geotools.feature.SchemaException;
034: import org.geotools.feature.type.GeometricAttributeType;
035: import org.geotools.resources.CRSUtilities;
036: import org.opengis.coverage.grid.GridCoverage;
037: import org.opengis.parameter.GeneralParameterValue;
038: import org.opengis.referencing.crs.CoordinateReferenceSystem;
039: import org.opengis.referencing.operation.MathTransform;
040: import org.opengis.referencing.operation.TransformException;
041:
042: import com.vividsolutions.jts.geom.Coordinate;
043: import com.vividsolutions.jts.geom.CoordinateSequence;
044: import com.vividsolutions.jts.geom.GeometryFactory;
045: import com.vividsolutions.jts.geom.LineString;
046: import com.vividsolutions.jts.geom.LinearRing;
047: import com.vividsolutions.jts.geom.Polygon;
048: import com.vividsolutions.jts.geom.PrecisionModel;
049:
050: /**
051: * A set of utilities methods for interactions between {@link GridCoverage}
052: * and {@link Feature}. Those methods are not really rigorous; must of them
053: * should be seen as temporary implementations.
054: *
055: * @since 2.4
056: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/resources/coverage/FeatureUtilities.java $
057: * @version $Id: FeatureUtilities.java 27037 2007-09-18 12:58:10Z simboss $
058: * @author Simone Giannecchini
059: */
060: public final class FeatureUtilities {
061: /**
062: * Do not allows instantiation of this class.
063: */
064: private FeatureUtilities() {
065: }
066:
067: /**
068: * Returns the polygon surrounding the specified rectangle.
069: * Code lifted from ArcGridDataSource (temporary).
070: */
071: private static Polygon getPolygon(final Rectangle2D rect) {
072: final PrecisionModel pm = new PrecisionModel();
073: final GeometryFactory gf = new GeometryFactory(pm, 0);
074: final Coordinate[] coord = new Coordinate[] {
075: new Coordinate(rect.getMinX(), rect.getMinY()),
076: new Coordinate(rect.getMaxX(), rect.getMinY()),
077: new Coordinate(rect.getMaxX(), rect.getMaxY()),
078: new Coordinate(rect.getMinX(), rect.getMaxY()),
079: new Coordinate(rect.getMinX(), rect.getMinY()) };
080: final LinearRing ring = gf.createLinearRing(coord);
081: return new Polygon(ring, null, gf);
082: }
083:
084: /**
085: * Wraps a grid coverage into a Feature. Code lifted from ArcGridDataSource
086: * (temporary).
087: *
088: * @param coverage the grid coverage.
089: * @return a feature with the grid coverage envelope as the geometry and the
090: * grid coverage itself in the "grid" attribute.
091: */
092: public static FeatureCollection wrapGridCoverage(
093: final GridCoverage2D coverage) throws TransformException,
094: SchemaException, IllegalAttributeException {
095: final Polygon bounds = getPolygon(coverage.getEnvelope2D());
096: final CoordinateReferenceSystem sourceCRS = CRSUtilities
097: .getCRS2D(coverage.getCoordinateReferenceSystem());
098:
099: // create the feature type
100: final GeometricAttributeType geom = new GeometricAttributeType(
101: "geom", Polygon.class, true, 1, 1, null, sourceCRS,
102: null);
103: final AttributeType grid = AttributeTypeFactory
104: .newAttributeType("grid", GridCoverage.class);
105:
106: final AttributeType[] attTypes = { geom, grid };
107: // Fix the schema name
108: final String typeName = "GridCoverage";
109: final DefaultFeatureType schema = (DefaultFeatureType) FeatureTypeBuilder
110: .newFeatureType(attTypes, typeName);
111:
112: // create the feature
113: Feature feature = schema
114: .create(new Object[] { bounds, coverage });
115:
116: final FeatureCollection collection = FeatureCollections
117: .newCollection();
118: collection.add(feature);
119:
120: return collection;
121: }
122:
123: /**
124: * Wraps a grid coverage into a Feature. Code lifted from ArcGridDataSource
125: * (temporary).
126: *
127: * @param reader the grid coverage reader.
128: * @return a feature with the grid coverage envelope as the geometry and the
129: * grid coverage itself in the "grid" attribute.
130: *
131: * @deprecated Please use FeatureUtilities#wrapGridCoverageReader(final AbstractGridCoverage2DReader gridCoverageReader, GeneralParameterValue[] params)
132: */
133: public static FeatureCollection wrapGridCoverageReader(
134: final AbstractGridCoverage2DReader gridCoverageReader)
135: throws TransformException, FactoryConfigurationError,
136: SchemaException, IllegalAttributeException {
137: // create surrounding polygon
138: final PrecisionModel pm = new PrecisionModel();
139: final GeometryFactory gf = new GeometryFactory(pm, 0);
140: final Rectangle2D rect = gridCoverageReader
141: .getOriginalEnvelope().toRectangle2D();
142: final CoordinateReferenceSystem sourceCrs = CRSUtilities
143: .getCRS2D(gridCoverageReader.getCrs());
144:
145: final Coordinate[] coord = new Coordinate[5];
146: coord[0] = new Coordinate(rect.getMinX(), rect.getMinY());
147: coord[1] = new Coordinate(rect.getMaxX(), rect.getMinY());
148: coord[2] = new Coordinate(rect.getMaxX(), rect.getMaxY());
149: coord[3] = new Coordinate(rect.getMinX(), rect.getMaxY());
150: coord[4] = new Coordinate(rect.getMinX(), rect.getMinY());
151:
152: // }
153: final LinearRing ring = gf.createLinearRing(coord);
154: final Polygon bounds = new Polygon(ring, null, gf);
155:
156: // create the feature type
157: final GeometricAttributeType geom = new GeometricAttributeType(
158: "geom", Polygon.class, true, 1, 1, null, sourceCrs,
159: null);
160: final AttributeType grid = AttributeTypeFactory
161: .newAttributeType("grid",
162: AbstractGridCoverage2DReader.class);
163:
164: final AttributeType[] attTypes = { geom, grid };
165: // Fix the schema name
166: final String typeName = "GridCoverage";
167: final DefaultFeatureType schema = (DefaultFeatureType) FeatureTypeBuilder
168: .newFeatureType(attTypes, typeName);
169:
170: // create the feature
171: Feature feature = schema.create(new Object[] { bounds,
172: gridCoverageReader });
173:
174: final FeatureCollection collection = FeatureCollections
175: .newCollection();
176: collection.add(feature);
177:
178: return collection;
179: }
180:
181: /**
182: * Wraps a grid coverage into a Feature. Code lifted from ArcGridDataSource
183: * (temporary).
184: *
185: * @param reader the grid coverage reader.
186: * @return a feature with the grid coverage envelope as the geometry and the
187: * grid coverage itself in the "grid" attribute.
188: */
189: public static FeatureCollection wrapGridCoverageReader(
190: final AbstractGridCoverage2DReader gridCoverageReader,
191: GeneralParameterValue[] params) throws TransformException,
192: FactoryConfigurationError, SchemaException,
193: IllegalAttributeException {
194:
195: // create surrounding polygon
196: final PrecisionModel pm = new PrecisionModel();
197: final GeometryFactory gf = new GeometryFactory(pm, 0);
198: final Rectangle2D rect = gridCoverageReader
199: .getOriginalEnvelope().toRectangle2D();
200: final CoordinateReferenceSystem sourceCrs = CRSUtilities
201: .getCRS2D(gridCoverageReader.getCrs());
202:
203: final Coordinate[] coord = new Coordinate[5];
204: coord[0] = new Coordinate(rect.getMinX(), rect.getMinY());
205: coord[1] = new Coordinate(rect.getMaxX(), rect.getMinY());
206: coord[2] = new Coordinate(rect.getMaxX(), rect.getMaxY());
207: coord[3] = new Coordinate(rect.getMinX(), rect.getMaxY());
208: coord[4] = new Coordinate(rect.getMinX(), rect.getMinY());
209:
210: // }
211: final LinearRing ring = gf.createLinearRing(coord);
212: final Polygon bounds = new Polygon(ring, null, gf);
213:
214: // create the feature type
215: final GeometricAttributeType geom = new GeometricAttributeType(
216: "geom", Polygon.class, true, 1, 1, null, sourceCrs,
217: null);
218: final AttributeType grid = AttributeTypeFactory
219: .newAttributeType("grid",
220: AbstractGridCoverage2DReader.class);
221: final AttributeType paramsAttr = AttributeTypeFactory
222: .newAttributeType("params",
223: GeneralParameterValue[].class);
224:
225: final AttributeType[] attTypes = { geom, grid, paramsAttr };
226: // Fix the schema name
227: final String typeName = "GridCoverage";
228: final DefaultFeatureType schema = (DefaultFeatureType) FeatureTypeBuilder
229: .newFeatureType(attTypes, typeName);
230:
231: // create the feature
232: Feature feature = schema.create(new Object[] { bounds,
233: gridCoverageReader, params });
234:
235: final FeatureCollection collection = FeatureCollections
236: .newCollection();
237: collection.add(feature);
238:
239: return collection;
240: }
241:
242: /**
243: * Converts a JTS {@link Polygon}, which represents a ROI, int an AWT
244: * {@link java.awt.Polygon} by means of the provided {@link MathTransform}.
245: *
246: * @param roiInput
247: * the input ROI as a JTS {@link Polygon}.
248: * @param worldToGridTransform
249: * the {@link MathTransform} to apply to the input ROI.
250: * @return an AWT {@link java.awt.Polygon}.
251: * @throws TransformException
252: * in case the provided {@link MathTransform} chokes.
253: */
254: public static java.awt.Polygon convertPolygon(
255: final Polygon roiInput, MathTransform worldToGridTransform)
256: throws TransformException {
257: return convertPolygonToPointArray(roiInput,
258: worldToGridTransform, null);
259: }
260:
261: /**
262: * Converts a JTS {@link Polygon}, which represents a ROI, int an AWT
263: * {@link java.awt.Polygon} by means of the provided {@link MathTransform}.
264: *
265: * <p>
266: * It also stores the points for this polygon into the provided {@link List}.
267: *
268: * @param roiInput
269: * the input ROI as a JTS {@link Polygon}.
270: * @param worldToGridTransform
271: * the {@link MathTransform} to apply to the input ROI.
272: * @param points
273: * a {@link List} that should hold the transformed points.
274: * @return an AWT {@link java.awt.Polygon}.
275: * @throws TransformException
276: * in case the provided {@link MathTransform} chokes.
277: */
278: public static java.awt.Polygon convertPolygonToPointArray(
279: final Polygon roiInput, MathTransform worldToGridTransform,
280: List/*<Double>*/points) throws TransformException {
281: final boolean isIdentity = worldToGridTransform.isIdentity();
282: final double coords[] = new double[2];
283: final LineString exteriorRing = roiInput.getExteriorRing();
284: final CoordinateSequence exteriorRingCS = exteriorRing
285: .getCoordinateSequence();
286: final int numCoords = exteriorRingCS.size();
287: final java.awt.Polygon retValue = new java.awt.Polygon();
288: for (int i = 0; i < numCoords; i++) {
289: // get the actual coord
290: coords[0] = exteriorRingCS.getX(i);
291: coords[1] = exteriorRingCS.getY(i);
292:
293: // transform it
294: if (!isIdentity)
295: worldToGridTransform.transform(coords, 0, coords, 0, 1);
296:
297: // send it back to the returned polygon
298: final int x = (int) (coords[0] + 0.5d);
299: final int y = (int) (int) (coords[1] + 0.5d);
300: if (points != null)
301: points.add(new Point2D.Double(x, y));
302:
303: // send it back to the returned polygon
304: retValue.addPoint(x, y);
305:
306: }
307:
308: // return the created polygon.
309: return retValue;
310: }
311: }
|