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: package org.geotools.geometry.jts;
017:
018: import java.awt.geom.AffineTransform;
019:
020: import org.opengis.referencing.operation.MathTransform;
021:
022: import com.vividsolutions.jts.geom.LineString;
023: import com.vividsolutions.jts.geom.LinearRing;
024: import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence;
025: import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence.Double;
026:
027: /**
028: * A path iterator for the LiteShape class, specialized to iterate over
029: * LineString object.
030: *
031: * @author Andrea Aime
032: * @author simone giannecchini * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/geometry/jts/PackedLineIterator.java $
033: * @version $Id: PackedLineIterator.java 25075 2007-04-09 19:20:46Z desruisseaux $
034: */
035: public final class PackedLineIterator extends AbstractLiteIterator {
036: /** Transform applied on the coordinates during iteration */
037: private AffineTransform at;
038:
039: /** The array of coordinates that represents the line geometry */
040: private PackedCoordinateSequence.Double coordinates = null;
041:
042: /** Current line coordinate */
043: private int currentCoord = 0;
044:
045: /** The previous coordinate (during iteration) */
046: private float oldX = Float.NaN;
047: private float oldY = Float.NaN;
048:
049: /** True when the iteration is terminated */
050: private boolean done = false;
051:
052: /** True if the line is a ring */
053: private boolean isClosed;
054:
055: /** If true, apply simple distance based generalization */
056: private boolean generalize = false;
057:
058: /** Maximum distance for point elision when generalizing */
059: private float maxDistance = 1.0f;
060:
061: /** Horizontal scale, got from the affine transform and cached */
062: private float xScale;
063:
064: /** Vertical scale, got from the affine transform and cached */
065: private float yScale;
066:
067: private int coordinateCount;
068:
069: /**
070: * Creates a new instance of LineIterator
071: *
072: * @param ls The line string the iterator will use
073: * @param at The affine transform applied to coordinates during iteration
074: */
075: public PackedLineIterator(LineString ls, AffineTransform at,
076: boolean generalize, float maxDistance) {
077: if (at == null) {
078: at = new AffineTransform();
079: }
080:
081: this .at = at;
082: xScale = (float) Math.sqrt((at.getScaleX() * at.getScaleX())
083: + (at.getShearX() * at.getShearX()));
084: yScale = (float) Math.sqrt((at.getScaleY() * at.getScaleY())
085: + (at.getShearY() * at.getShearY()));
086:
087: coordinates = (Double) ls.getCoordinateSequence();
088: coordinateCount = coordinates.size();
089: isClosed = ls instanceof LinearRing;
090:
091: this .generalize = generalize;
092: this .maxDistance = maxDistance;
093: }
094:
095: /**
096: * Creates a new instance of LineIterator
097: *
098: * @param ls The line string the iterator will use
099: * @param at The affine transform applied to coordinates during iteration
100: * @param generalize if true apply simple distance based generalization
101: */
102: // public LineIterator(LineString ls, AffineTransform at, boolean generalize) {
103: // this(ls, at);
104: //
105: // }
106: /**
107: * Creates a new instance of LineIterator
108: *
109: * @param ls The line string the iterator will use
110: * @param at The affine transform applied to coordinates during iteration
111: * @param generalize if true apply simple distance based generalization
112: * @param maxDistance during iteration, a point will be skipped if it's
113: * distance from the previous is less than maxDistance
114: */
115: // public LineIterator(
116: // LineString ls, AffineTransform at, boolean generalize,
117: // double maxDistance) {
118: // this(ls, at, generalize);
119: //
120: // }
121: /**
122: * Sets the distance limit for point skipping during distance based
123: * generalization
124: *
125: * @param distance the maximum distance for point skipping
126: */
127: public void setMaxDistance(float distance) {
128: maxDistance = distance;
129: }
130:
131: /**
132: * Returns the distance limit for point skipping during distance based
133: * generalization
134: *
135: * @return the maximum distance for distance based generalization
136: */
137: public double getMaxDistance() {
138: return maxDistance;
139: }
140:
141: /**
142: * Returns the coordinates and type of the current path segment in the
143: * iteration. The return value is the path-segment type: SEG_MOVETO,
144: * SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A double array of
145: * length 6 must be passed in and can be used to store the coordinates of
146: * the point(s). Each point is stored as a pair of double x,y coordinates.
147: * SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns
148: * two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return
149: * any points.
150: *
151: * @param coords an array that holds the data returned from this method
152: *
153: * @return the path-segment type of the current path segment.
154: *
155: * @see #SEG_MOVETO
156: * @see #SEG_LINETO
157: * @see #SEG_QUADTO
158: * @see #SEG_CUBICTO
159: * @see #SEG_CLOSE
160: */
161: public int currentSegment(float[] coords) {
162: if (currentCoord == 0) {
163: coords[0] = (float) coordinates.getX(0);
164: coords[1] = (float) coordinates.getY(0);
165: at.transform(coords, 0, coords, 0, 1);
166:
167: return SEG_MOVETO;
168: } else if ((currentCoord == coordinateCount) && isClosed) {
169: return SEG_CLOSE;
170: } else {
171: coords[0] = (float) coordinates.getX(currentCoord);
172: coords[1] = (float) coordinates.getY(currentCoord);
173: at.transform(coords, 0, coords, 0, 1);
174:
175: return SEG_LINETO;
176: }
177: }
178:
179: // /**
180: // * Returns the coordinates and type of the current path segment in the
181: // * iteration. The return value is the path-segment type: SEG_MOVETO,
182: // * SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A float array of
183: // * length 6 must be passed in and can be used to store the coordinates of
184: // * the point(s). Each point is stored as a pair of float x,y coordinates.
185: // * SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns
186: // * two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return
187: // * any points.
188: // *
189: // * @param coords an array that holds the data returned from this method
190: // *
191: // * @return the path-segment type of the current path segment.
192: // *
193: // * @see #SEG_MOVETO
194: // * @see #SEG_LINETO
195: // * @see #SEG_QUADTO
196: // * @see #SEG_CUBICTO
197: // * @see #SEG_CLOSE
198: // */
199: // public int currentSegment(float[] coords) {
200: // double[] dcoords = new double[2];
201: // int result = currentSegment(dcoords);
202: // coords[0] = (float) dcoords[0];
203: // coords[1] = (float) dcoords[1];
204: //
205: // return result;
206: // }
207:
208: /**
209: * Returns the winding rule for determining the interior of the path.
210: *
211: * @return the winding rule.
212: *
213: * @see #WIND_EVEN_ODD
214: * @see #WIND_NON_ZERO
215: */
216: public int getWindingRule() {
217: return WIND_NON_ZERO;
218: }
219:
220: /**
221: * Tests if the iteration is complete.
222: *
223: * @return <code>true</code> if all the segments have been read;
224: * <code>false</code> otherwise.
225: */
226: public boolean isDone() {
227: return done;
228: }
229:
230: /**
231: * Moves the iterator to the next segment of the path forwards along the
232: * primary direction of traversal as long as there are more points in that
233: * direction.
234: */
235: public void next() {
236: if (((currentCoord == (coordinateCount - 1)) && !isClosed)
237: || ((currentCoord == coordinateCount) && isClosed)) {
238: done = true;
239: } else {
240: if (generalize) {
241: if (Float.isNaN(oldX)) {
242: currentCoord++;
243: oldX = (float) coordinates.getX(currentCoord);
244: oldY = (float) coordinates.getY(currentCoord);
245: } else {
246: float distx = 0;
247: float disty = 0;
248: float x = 0;
249: float y = 0;
250:
251: do {
252: currentCoord++;
253: x = (float) coordinates.getX(currentCoord);
254: y = (float) coordinates.getY(currentCoord);
255:
256: if (currentCoord < coordinateCount) {
257: distx = Math.abs(x - oldX);
258: disty = Math.abs(y - oldY);
259: }
260: } while (((distx * xScale) < maxDistance)
261: && ((disty * yScale) < maxDistance)
262: && ((!isClosed && (currentCoord < (coordinateCount - 1))) || (isClosed && (currentCoord < coordinateCount))));
263:
264: if (currentCoord < coordinateCount) {
265: oldX = x;
266: oldY = y;
267: } else {
268: oldX = Float.NaN;
269: oldY = Float.NaN;
270: }
271: }
272: } else {
273: currentCoord++;
274: }
275: }
276: }
277:
278: /**
279: * @see java.awt.geom.PathIterator#currentSegment(double[])
280: */
281: public int currentSegment(double[] coords) {
282: System.out.println("Double!");
283: return 0;
284: }
285:
286: }
|