001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, 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:
017: package org.geotools.geometry.jts;
018:
019: import java.awt.Shape;
020: import java.awt.geom.AffineTransform;
021: import java.awt.geom.PathIterator;
022:
023: import org.opengis.referencing.operation.MathTransform;
024:
025: import com.vividsolutions.jts.geom.Geometry;
026: import com.vividsolutions.jts.geom.GeometryCollection;
027: import com.vividsolutions.jts.geom.LineString;
028: import com.vividsolutions.jts.geom.LinearRing;
029: import com.vividsolutions.jts.geom.Point;
030: import com.vividsolutions.jts.geom.Polygon;
031:
032: /**
033: * A path iterator for the LiteShape class, specialized to iterate over a
034: * geometry collection. It can be seen as a composite, since uses in fact
035: * other, simpler iterator to carry on its duties.
036: *
037: * @author Andrea Aime
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/geometry/jts/GeomCollectionIterator.java $
039: * @version $Id: GeomCollectionIterator.java 25086 2007-04-10 08:54:25Z aaime $
040: */
041: public final class GeomCollectionIterator extends AbstractLiteIterator {
042: /** Transform applied on the coordinates during iteration */
043: private AffineTransform at;
044:
045: /** The set of geometries that we will iterate over */
046: private GeometryCollection gc;
047:
048: /** The current geometry */
049: private int currentGeom;
050:
051: /** The current sub-iterator */
052: private PathIterator currentIterator;
053:
054: /** True when the iterator is terminate */
055: private boolean done = false;
056:
057: /** If true, apply simple distance based generalization */
058: private boolean generalize = false;
059:
060: /** Maximum distance for point elision when generalizing */
061: private double maxDistance = 1.0;
062:
063: private LineIterator lineIterator = new LineIterator();
064:
065: private EmptyIterator emptyIterator = new EmptyIterator();
066:
067: public GeomCollectionIterator() {
068:
069: }
070:
071: /**
072: * @param gc
073: * @param at
074: */
075: public void init(GeometryCollection gc, AffineTransform at,
076: boolean generalize, double maxDistance) {
077: this .gc = gc;
078: this .at = at == null ? new AffineTransform() : at;
079: this .generalize = generalize;
080: this .maxDistance = maxDistance;
081: currentGeom = 0;
082: done = false;
083: currentIterator = gc.isEmpty() ? emptyIterator : getIterator(gc
084: .getGeometryN(0));
085: }
086:
087: /**
088: * Creates a new instance of GeomCollectionIterator
089: *
090: * @param gc The geometry collection the iterator will use
091: * @param at The affine transform applied to coordinates during iteration
092: * @param generalize if true apply simple distance based generalization
093: * @param maxDistance during iteration, a point will be skipped if it's
094: * distance from the previous is less than maxDistance
095: */
096: public GeomCollectionIterator(GeometryCollection gc,
097: AffineTransform at, boolean generalize, double maxDistance) {
098: init(gc, at, generalize, maxDistance);
099: }
100:
101: /**
102: * Sets the distance limit for point skipping during distance based
103: * generalization
104: *
105: * @param distance the maximum distance for point skipping
106: */
107: public void setMaxDistance(double distance) {
108: maxDistance = distance;
109: }
110:
111: /**
112: * Returns the distance limit for point skipping during distance based
113: * generalization
114: *
115: * @return the maximum distance for distance based generalization
116: */
117: public double getMaxDistance() {
118: return maxDistance;
119: }
120:
121: /**
122: * Returns the specific iterator for the geometry passed.
123: *
124: * @param g The geometry whole iterator is requested
125: *
126: * @return the specific iterator for the geometry passed.
127: */
128: private AbstractLiteIterator getIterator(Geometry g) {
129: AbstractLiteIterator pi = null;
130:
131: if (g.isEmpty())
132: return emptyIterator;
133: if (g instanceof Polygon) {
134: Polygon p = (Polygon) g;
135: pi = new PolygonIterator(p, at, generalize, maxDistance);
136: } else if (g instanceof GeometryCollection) {
137: GeometryCollection gc = (GeometryCollection) g;
138: pi = new GeomCollectionIterator(gc, at, generalize,
139: maxDistance);
140: } else if (g instanceof LineString) {
141: LineString ls = (LineString) g;
142: lineIterator.init(ls, at, generalize, (float) maxDistance);
143: pi = lineIterator;
144: } else if (g instanceof LinearRing) {
145: LinearRing lr = (LinearRing) g;
146: lineIterator.init(lr, at, generalize, (float) maxDistance);
147: pi = lineIterator;
148: } else if (g instanceof Point) {
149: Point p = (Point) g;
150: pi = new PointIterator(p, at);
151: }
152:
153: return pi;
154: }
155:
156: /**
157: * Returns the coordinates and type of the current path segment in the
158: * iteration. The return value is the path-segment type: SEG_MOVETO,
159: * SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A double array of
160: * length 6 must be passed in and can be used to store the coordinates of
161: * the point(s). Each point is stored as a pair of double x,y coordinates.
162: * SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns
163: * two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return
164: * any points.
165: *
166: * @param coords an array that holds the data returned from this method
167: *
168: * @return the path-segment type of the current path segment.
169: *
170: * @see #SEG_MOVETO
171: * @see #SEG_LINETO
172: * @see #SEG_QUADTO
173: * @see #SEG_CUBICTO
174: * @see #SEG_CLOSE
175: */
176: public int currentSegment(double[] coords) {
177: return currentIterator.currentSegment(coords);
178: }
179:
180: /**
181: * Returns the coordinates and type of the current path segment in the
182: * iteration. The return value is the path-segment type: SEG_MOVETO,
183: * SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A float array of
184: * length 6 must be passed in and can be used to store the coordinates of
185: * the point(s). Each point is stored as a pair of float x,y coordinates.
186: * SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns
187: * two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return
188: * any points.
189: *
190: * @param coords an array that holds the data returned from this method
191: *
192: * @return the path-segment type of the current path segment.
193: *
194: * @see #SEG_MOVETO
195: * @see #SEG_LINETO
196: * @see #SEG_QUADTO
197: * @see #SEG_CUBICTO
198: * @see #SEG_CLOSE
199: */
200: public int currentSegment(float[] coords) {
201: return currentIterator.currentSegment(coords);
202: }
203:
204: /**
205: * Returns the winding rule for determining the interior of the path.
206: *
207: * @return the winding rule.
208: *
209: * @see #WIND_EVEN_ODD
210: * @see #WIND_NON_ZERO
211: */
212: public int getWindingRule() {
213: return WIND_NON_ZERO;
214: }
215:
216: /**
217: * Tests if the iteration is complete.
218: *
219: * @return <code>true</code> if all the segments have been read;
220: * <code>false</code> otherwise.
221: */
222: public boolean isDone() {
223: return done;
224: }
225:
226: /**
227: * Moves the iterator to the next segment of the path forwards along the
228: * primary direction of traversal as long as there are more points in that
229: * direction.
230: */
231: public void next() {
232: if (currentIterator.isDone()) {
233: if (currentGeom < (gc.getNumGeometries() - 1)) {
234: currentGeom++;
235: currentIterator = getIterator(gc
236: .getGeometryN(currentGeom));
237: } else {
238: done = true;
239: }
240: } else {
241: currentIterator.next();
242: }
243: }
244:
245: }
|