Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / core / gt2 / PolygonIterator.java @ 10627

History | View | Annotate | Download (8.11 KB)

1
/*
2
 *    Geotools2 - OpenSource mapping toolkit
3
 *    http://geotools.org
4
 *    (C) 2002, Geotools Project Managment Committee (PMC)
5
 *
6
 *    This library is free software; you can redistribute it and/or
7
 *    modify it under the terms of the GNU Lesser General Public
8
 *    License as published by the Free Software Foundation;
9
 *    version 2.1 of the License.
10
 *
11
 *    This library is distributed in the hope that it will be useful,
12
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 *    Lesser General Public License for more details.
15
 *
16
 */
17
package com.iver.cit.gvsig.fmap.core.gt2;
18

    
19
import java.awt.geom.AffineTransform;
20

    
21
import com.vividsolutions.jts.geom.Coordinate;
22
import com.vividsolutions.jts.geom.CoordinateSequence;
23
import com.vividsolutions.jts.geom.LineString;
24
import com.vividsolutions.jts.geom.Polygon;
25

    
26

    
27
/**
28
 * A path iterator for the LiteShape class, specialized to iterate over Polygon
29
 * objects.
30
 *
31
 * @author Andrea Aime
32
 * @version $Id: PolygonIterator.java 10627 2007-03-06 17:10:21Z caballero $
33
 */
34
class PolygonIterator extends AbstractLiteIterator {
35
    /** Transform applied on the coordinates during iteration */
36
    private AffineTransform at;
37

    
38
    /** The rings describing the polygon geometry */
39
    private LineString[] rings;
40

    
41
    /** The current ring during iteration */
42
    private int currentRing = 0;
43

    
44
    /** Current line coordinate */
45
    private int currentCoord = 0;
46

    
47
    /** The array of coordinates that represents the line geometry */
48
    private CoordinateSequence coords = null;
49

    
50
    /** The previous coordinate (during iteration) */
51
    private Coordinate oldCoord = null;
52

    
53
    /** True when the iteration is terminated */
54
    private boolean done = false;
55

    
56
    /** If true, apply simple distance based generalization */
57
    private boolean generalize = false;
58

    
59
    /** Maximum distance for point elision when generalizing */
60
    private double maxDistance = 1.0;
61

    
62
    /** Horizontal scale, got from the affine transform and cached */
63
    private double xScale;
64

    
65
    /** Vertical scale, got from the affine transform and cached */
66
    private double yScale;
67

    
68
    /**
69
     * Creates a new PolygonIterator object.
70
     *
71
     * @param p The polygon
72
     * @param at The affine transform applied to coordinates during iteration
73
     */
74
    public PolygonIterator(Polygon p, AffineTransform at) {
75
        int numInteriorRings = p.getNumInteriorRing();
76
        rings = new LineString[numInteriorRings + 1];
77
        rings[0] = p.getExteriorRing();
78

    
79
        for (int i = 0; i < numInteriorRings; i++) {
80
            rings[i + 1] = p.getInteriorRingN(i);
81
        }
82

    
83
        if (at == null) {
84
            at = new AffineTransform();
85
        }
86

    
87
        this.at = at;
88
        xScale = Math.sqrt((at.getScaleX() * at.getScaleX())
89
                + (at.getShearX() * at.getShearX()));
90
        yScale = Math.sqrt((at.getScaleY() * at.getScaleY())
91
                + (at.getShearY() * at.getShearY()));
92

    
93
        coords = rings[0].getCoordinateSequence();
94
    }
95

    
96
    /**
97
     * Creates a new PolygonIterator object.
98
     *
99
     * @param p The polygon
100
     * @param at The affine transform applied to coordinates during iteration
101
     * @param generalize if true apply simple distance based generalization
102
     */
103
    public PolygonIterator(Polygon p, AffineTransform at, boolean generalize) {
104
        this(p, at);
105
        this.generalize = generalize;
106
    }
107

    
108
    /**
109
     * Creates a new PolygonIterator object.
110
     *
111
     * @param p The polygon
112
     * @param at The affine transform applied to coordinates during iteration
113
     * @param generalize if true apply simple distance based generalization
114
     * @param maxDistance during iteration, a point will be skipped if it's
115
     *        distance from the previous is less than maxDistance
116
     */
117
    public PolygonIterator(Polygon p, AffineTransform at, boolean generalize,
118
        double maxDistance) {
119
        this(p, at, generalize);
120
        this.maxDistance = maxDistance;
121
    }
122

    
123
    /**
124
     * Sets the distance limit for point skipping during distance based
125
     * generalization
126
     *
127
     * @param distance the maximum distance for point skipping
128
     */
129
    public void setMaxDistance(double distance) {
130
        maxDistance = distance;
131
    }
132

    
133
    /**
134
     * Returns the distance limit for point skipping during distance based
135
     * generalization
136
     *
137
     * @return the maximum distance for distance based generalization
138
     */
139
    public double getMaxDistance() {
140
        return maxDistance;
141
    }
142

    
143
    /**
144
     * Returns the coordinates and type of the current path segment in the
145
     * iteration. The return value is the path-segment type: SEG_MOVETO,
146
     * SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A double array of
147
     * length 6 must be passed in and can be used to store the coordinates of
148
     * the point(s). Each point is stored as a pair of double x,y coordinates.
149
     * SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns
150
     * two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return
151
     * any points.
152
     *
153
     * @param coords an array that holds the data returned from this method
154
     *
155
     * @return the path-segment type of the current path segment.
156
     *
157
     * @see #SEG_MOVETO
158
     * @see #SEG_LINETO
159
     * @see #SEG_QUADTO
160
     * @see #SEG_CUBICTO
161
     * @see #SEG_CLOSE
162
     */
163
    public int currentSegment(double[] coords) {
164
        if (currentCoord == 0) {
165
            coords[0] = this.coords.getX(0);
166
            coords[1] = this.coords.getY(0);
167
            transform(coords, 0, coords, 0, 1);
168

    
169
            return SEG_MOVETO;
170
        } else if (currentCoord == this.coords.size()) {
171
            return SEG_CLOSE;
172
        } else {
173
            coords[0] = this.coords.getX(currentCoord);
174
            coords[1] = this.coords.getY(currentCoord);
175
            transform(coords, 0, coords, 0, 1);
176

    
177
            return SEG_LINETO;
178
        }
179
    }
180
    
181
    protected void transform(double[] src, int index, double[] dest, int destIndex, int numPoints){
182
            at.transform(src, index, dest, destIndex, numPoints);
183
    }
184

    
185
    /**
186
     * Return the winding rule for determining the interior of the path.
187
     *
188
     * @return <code>WIND_EVEN_ODD</code> by default.
189
     */
190
    public int getWindingRule() {
191
        return WIND_EVEN_ODD;
192
    }
193

    
194
    /**
195
     * Tests if the iteration is complete.
196
     *
197
     * @return <code>true</code> if all the segments have been read;
198
     *         <code>false</code> otherwise.
199
     */
200
    public boolean isDone() {
201
        return done;
202
    }
203

    
204
    /**
205
     * Moves the iterator to the next segment of the path forwards along the
206
     * primary direction of traversal as long as there are more points in that
207
     * direction.
208
     */
209
    public void next() {
210
        if (currentCoord == coords.size()) {
211
            if (currentRing < (rings.length - 1)) {
212
                currentCoord = 0;
213
                currentRing++;
214
                coords = rings[currentRing].getCoordinateSequence();
215
            } else {
216
                done = true;
217
            }
218
        } else {
219
            if (generalize) {
220
                if (oldCoord == null) {
221
                    currentCoord++;
222
                    oldCoord = coords.getCoordinate(currentCoord);
223
                } else {
224
                    double distx = 0;
225
                    double disty = 0;
226

    
227
                    do {
228
                        currentCoord++;
229

    
230
                        if (currentCoord < coords.size()) {
231
                            distx = Math.abs(coords.getX(currentCoord)
232
                                    - oldCoord.x);
233
                            disty = Math.abs(coords.getY(currentCoord)
234
                                    - oldCoord.y);
235
                        }
236
                    } while (((distx * xScale) < maxDistance)
237
                            && ((disty * yScale) < maxDistance)
238
                            && (currentCoord < coords.size()));
239

    
240
                    if (currentCoord < coords.size()) {
241
                        oldCoord = coords.getCoordinate(currentCoord);
242
                    } else {
243
                        oldCoord = null;
244
                    }
245
                }
246
            } else {
247
                currentCoord++;
248
            }
249
        }
250
    }
251
    
252
}