/*
* OrbisGIS is a GIS application dedicated to scientific spatial simulation.
* This cross-platform GIS is developed at French IRSTV institute and is able
* to manipulate and create vector and raster spatial information. OrbisGIS
* is distributed under GPL 3 license. It is produced by the geo-informatic team of
* the IRSTV Institute , CNRS FR 2488:
* Erwan BOCHER, scientific researcher,
* Thomas LEDUC, scientific researcher,
* Fernando GONZALEZ CORTES, computer engineer.
*
* Copyright (C) 2007 Erwan BOCHER, Fernando GONZALEZ CORTES, Thomas LEDUC
*
* This file is part of OrbisGIS.
*
* OrbisGIS 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.
*
* OrbisGIS 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 OrbisGIS. If not, see .
*
* For more information, please consult:
*
*
*
* or contact directly:
* erwan.bocher _at_ ec-nantes.fr
* fergonco _at_ gmail.com
* thomas.leduc _at_ cerma.archi.fr
*/
/*
* GeoTools - OpenSource mapping toolkit
* http://geotools.org
* (C) 2004-2006, Geotools Project Managment Committee (PMC)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.orbisgis.renderer.liteShape;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* A path iterator for the LiteShape class, specialized to iterate over a
* geometry collection. It can be seen as a composite, since uses in fact other,
* simpler iterator to carry on its duties.
*
* @author Andrea Aime
* @source $URL:
* http://svn.geotools.org/geotools/tags/2.3.1/module/render/src/org/geotools/renderer/lite/GeomCollectionIterator.java $
* @version $Id: GeomCollectionIterator.java 20874 2006-08-07 10:00:01Z jgarnett $
*/
public final class GeomCollectionIterator extends AbstractLiteIterator {
/** Transform applied on the coordinates during iteration */
private AffineTransform at;
/** The set of geometries that we will iterate over */
private GeometryCollection gc;
/** The current geometry */
private int currentGeom;
/** The current sub-iterator */
private PathIterator currentIterator;
/** True when the iterator is terminate */
private boolean done = false;
/** If true, apply simple distance based generalization */
private boolean generalize = false;
/** Maximum distance for point elision when generalizing */
private double maxDistance = 1.0;
private LineIterator lineIterator = new LineIterator();
public GeomCollectionIterator() {
}
/**
* @param gc
* @param at
*/
public void init(GeometryCollection gc, AffineTransform at,
boolean generalize, double maxDistance) {
this.gc = gc;
this.at = at == null ? new AffineTransform() : at;
this.generalize = generalize;
this.maxDistance = maxDistance;
currentGeom = 0;
done = false;
currentIterator = getIterator(gc.getGeometryN(0));
}
/**
* Creates a new instance of GeomCollectionIterator
*
* @param gc
* The geometry collection the iterator will use
* @param at
* The affine transform applied to coordinates during iteration
* @param generalize
* if true apply simple distance based generalization
* @param maxDistance
* during iteration, a point will be skipped if it's distance
* from the previous is less than maxDistance
*/
public GeomCollectionIterator(GeometryCollection gc, AffineTransform at,
boolean generalize, double maxDistance) {
init(gc, at, generalize, maxDistance);
}
/**
* Sets the distance limit for point skipping during distance based
* generalization
*
* @param distance
* the maximum distance for point skipping
*/
public void setMaxDistance(double distance) {
maxDistance = distance;
}
/**
* Returns the distance limit for point skipping during distance based
* generalization
*
* @return the maximum distance for distance based generalization
*/
public double getMaxDistance() {
return maxDistance;
}
/**
* Returns the specific iterator for the geometry passed.
*
* @param g
* The geometry whole iterator is requested
*
* @return the specific iterator for the geometry passed.
*/
private AbstractLiteIterator getIterator(Geometry g) {
AbstractLiteIterator pi = null;
if (g instanceof Polygon) {
Polygon p = (Polygon) g;
pi = new PolygonIterator(p, at, generalize, maxDistance);
} else if (g instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) g;
pi = new GeomCollectionIterator(gc, at, generalize, maxDistance);
} else if (g instanceof LineString) {
LineString ls = (LineString) g;
lineIterator.init(ls, at, generalize, (float) maxDistance);
pi = lineIterator;
} else if (g instanceof LinearRing) {
LinearRing lr = (LinearRing) g;
lineIterator.init(lr, at, generalize, (float) maxDistance);
pi = lineIterator;
} else if (g instanceof Point) {
Point p = (Point) g;
pi = new PointIterator(p, at);
}
return pi;
}
/**
* Returns the coordinates and type of the current path segment in the
* iteration. The return value is the path-segment type: SEG_MOVETO,
* SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A double array of
* length 6 must be passed in and can be used to store the coordinates of
* the point(s). Each point is stored as a pair of double x,y coordinates.
* SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns two
* points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return any
* points.
*
* @param coords
* an array that holds the data returned from this method
*
* @return the path-segment type of the current path segment.
*
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(double[] coords) {
return currentIterator.currentSegment(coords);
}
/**
* Returns the coordinates and type of the current path segment in the
* iteration. The return value is the path-segment type: SEG_MOVETO,
* SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A float array of
* length 6 must be passed in and can be used to store the coordinates of
* the point(s). Each point is stored as a pair of float x,y coordinates.
* SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns two
* points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return any
* points.
*
* @param coords
* an array that holds the data returned from this method
*
* @return the path-segment type of the current path segment.
*
* @see #SEG_MOVETO
* @see #SEG_LINETO
* @see #SEG_QUADTO
* @see #SEG_CUBICTO
* @see #SEG_CLOSE
*/
public int currentSegment(float[] coords) {
return currentIterator.currentSegment(coords);
}
/**
* Returns the winding rule for determining the interior of the path.
*
* @return the winding rule.
*
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public int getWindingRule() {
return WIND_EVEN_ODD;
}
/**
* Tests if the iteration is complete.
*
* @return true if all the segments have been read;
* false otherwise.
*/
public boolean isDone() {
return done;
}
/**
* Moves the iterator to the next segment of the path forwards along the
* primary direction of traversal as long as there are more points in that
* direction.
*/
public void next() {
if (currentIterator.isDone()) {
if (currentGeom < (gc.getNumGeometries() - 1)) {
currentGeom++;
currentIterator = getIterator(gc.getGeometryN(currentGeom));
} else {
done = true;
}
} else {
currentIterator.next();
}
}
}