001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-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;
009: * version 2.1 of the License.
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.gml;
017:
018: // Java Topology Suite dependencies
019: import java.util.ArrayList;
020: import java.util.logging.Logger;
021:
022: import com.vividsolutions.jts.geom.Coordinate;
023: import com.vividsolutions.jts.geom.Geometry;
024: import com.vividsolutions.jts.geom.GeometryFactory;
025: import com.vividsolutions.jts.geom.LinearRing;
026: import com.vividsolutions.jts.geom.Polygon;
027: import com.vividsolutions.jts.geom.TopologyException;
028:
029: /**
030: * Creates a Polygon geometry.
031: *
032: * @author Ian Turton, CCG
033: * @author Rob Hranac, Vision for New York
034: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/gml/SubHandlerPolygon.java $
035: * @version $Id: SubHandlerPolygon.java 27862 2007-11-12 19:51:19Z desruisseaux $
036: */
037: public class SubHandlerPolygon extends SubHandler {
038: /** The logger for the GML module. */
039: private static final Logger LOGGER = org.geotools.util.logging.Logging
040: .getLogger("org.geotools.gml");
041: protected static com.vividsolutions.jts.algorithm.CGAlgorithms cga = new com.vividsolutions.jts.algorithm.RobustCGAlgorithms();
042:
043: /** Factory for creating the Polygon geometry. */
044: private GeometryFactory geometryFactory = new GeometryFactory();
045:
046: /** Handler for the LinearRings that comprise the Polygon. */
047: private SubHandlerLinearRing currentHandler = new SubHandlerLinearRing();
048:
049: /** Stores Polygon's outer boundary (shell). */
050: private LinearRing outerBoundary = null;
051:
052: /** Stores Polygon's inner boundaries (holes). */
053: private ArrayList innerBoundaries = new ArrayList();
054:
055: /**
056: * Remembers the current location in the parsing stream (inner or outer
057: * boundary).
058: */
059: private int location = 0;
060:
061: /** Indicates that we are inside the inner boundary of the Polygon. */
062: private int INNER_BOUNDARY = 1;
063:
064: /** Indicates that we are inside the outer boundary of the Polygon. */
065: private int OUTER_BOUNDARY = 2;
066:
067: /**
068: * Creates a new instance of GMLPolygonHandler.
069: */
070: public SubHandlerPolygon() {
071: }
072:
073: /**
074: * Catches inner and outer LinearRings messages and handles them
075: * appropriately.
076: *
077: * @param message Name of sub geometry located.
078: * @param type Type of sub geometry located.
079: */
080: public void subGeometry(String message, int type) {
081: // if we have found a linear ring, either
082: // add it to the list of inner boundaries if we are reading them
083: // and at the end of the LinearRing
084: // add it to the outer boundary if we are reading it and at the end of
085: // the LinearRing
086: // create a new linear ring, if we are at the start of a new linear ring
087: if (message.equals("LinearRing")) {
088: if (type == GEOMETRY_END) {
089: if (location == INNER_BOUNDARY) {
090: LinearRing ring = (LinearRing) currentHandler
091: .create(geometryFactory);
092: Coordinate[] points = ring.getCoordinates();
093:
094: /* it is important later that internal rings (holes) are
095: * anticlockwise (counter clockwise) - so we reverse the
096: * points if necessary
097: */
098: if (cga.isCCW(points)) {
099: LOGGER.finer("good hole found");
100:
101: //System.out.println("inner boundary: " + message);
102: innerBoundaries.add(ring);
103:
104: } else {
105: LOGGER.finer("bad hole found - fixing");
106: Coordinate[] newPoints = new Coordinate[points.length];
107:
108: for (int i = 0, j = points.length - 1; i < points.length; i++, j--) {
109: newPoints[i] = points[j];
110: }
111:
112: try {
113: ring = geometryFactory
114: .createLinearRing(newPoints);
115: innerBoundaries.add(ring);
116: } catch (TopologyException e) {
117: LOGGER
118: .warning("Caught Topology exception in GMLPolygonHandler");
119: ring = null;
120: }
121: }
122: } else if (location == OUTER_BOUNDARY) {
123: /* it is important later that the outerboundary is
124: * clockwise - so we reverse the
125: * points if necessary
126: */
127: outerBoundary = (LinearRing) currentHandler
128: .create(geometryFactory);
129:
130: Coordinate[] points = outerBoundary
131: .getCoordinates();
132:
133: if (cga.isCCW(points)) {
134: LOGGER.finer("bad outer ring - rebuilding");
135: // System.out.println("rebuilding outer ring");
136: Coordinate[] newPoints = new Coordinate[points.length];
137:
138: for (int i = 0, j = points.length - 1; i < points.length; i++, j--) {
139: newPoints[i] = points[j];
140: }
141:
142: try {
143: outerBoundary = geometryFactory
144: .createLinearRing(newPoints);
145: //System.out.println("outer boundary: " + message);
146:
147: } catch (TopologyException e) {
148: LOGGER
149: .warning("Caught Topology exception in "
150: + "GMLPolygonHandler");
151: outerBoundary = null;
152: }
153: }
154: }
155: } else if (type == GEOMETRY_START) {
156: currentHandler = new SubHandlerLinearRing();
157: }
158: } else if (message.equals("outerBoundaryIs")) {
159: // or, if we are getting notice of an inner/outer boundary marker,
160: // set current location appropriately
161: LOGGER.finer("new outer Boundary");
162: location = OUTER_BOUNDARY;
163: } else if (message.equals("innerBoundaryIs")) {
164: LOGGER.finer("new InnerBoundary");
165: location = INNER_BOUNDARY;
166: }
167: }
168:
169: /**
170: * Adds a coordinate to the current LinearRing.
171: *
172: * @param coordinate Name of sub geometry located.
173: */
174: public void addCoordinate(Coordinate coordinate) {
175: currentHandler.addCoordinate(coordinate);
176: }
177:
178: /**
179: * Determines whether or not the geometry is ready to be returned.
180: *
181: * @param message Name of GML element that prompted this check.
182: *
183: * @return Flag indicating whether or not the geometry is ready to be
184: * returned.
185: */
186: public boolean isComplete(String message) {
187: // the conditions checked here are that the endGeometry message that
188: // prompted this check is a Polygon and that this Polygon has an outer
189: // boundary; if true, then return the all go signal
190: if (message.equals("Polygon")) {
191: if (outerBoundary != null) {
192: return true;
193: } else {
194: return false;
195: }
196: }
197: // otherwise, send this message to the subGeometry method for further
198: // processing
199: else {
200: // this.subGeometry(message, GEOMETRY_END);
201:
202: return false;
203: }
204: }
205:
206: /**
207: * Returns the completed OGC Polygon.
208: *
209: * @param geometryFactory Geometry factory to be used in Polygon creation.
210: *
211: * @return Completed OGC Polygon.
212: */
213: public Geometry create(GeometryFactory geometryFactory) {
214: for (int i = 0; i < innerBoundaries.size(); i++) {
215: LinearRing hole = (LinearRing) innerBoundaries.get(i);
216: if (hole.crosses(outerBoundary)) {
217: LOGGER.warning("Topology Error building polygon");
218:
219: return null;
220: }
221: }
222:
223: LinearRing[] rings = (LinearRing[]) innerBoundaries
224: .toArray(new LinearRing[innerBoundaries.size()]);
225: Polygon polygon = geometryFactory.createPolygon(outerBoundary,
226: rings);
227: polygon.setUserData(getSRS());
228: polygon.setSRID(getSRID());
229: return polygon;
230: }
231: }
|