/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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.geotools.gml; // Java Topology Suite dependencies import java.util.ArrayList; import java.util.logging.Logger; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.TopologyException; /** * Creates a Polygon geometry. * * @author Ian Turton, CCG * @author Rob Hranac, Vision for New York * * @source $URL$ * @version $Id$ */ public class SubHandlerPolygon extends SubHandler { /** The logger for the GML module. */ private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.gml"); protected static com.vividsolutions.jts.algorithm.CGAlgorithms cga = new com.vividsolutions.jts.algorithm.RobustCGAlgorithms(); /** Factory for creating the Polygon geometry. */ private GeometryFactory geometryFactory = new GeometryFactory(); /** Handler for the LinearRings that comprise the Polygon. */ private SubHandlerLinearRing currentHandler = new SubHandlerLinearRing(); /** Stores Polygon's outer boundary (shell). */ private LinearRing outerBoundary = null; /** Stores Polygon's inner boundaries (holes). */ private ArrayList innerBoundaries = new ArrayList(); /** * Remembers the current location in the parsing stream (inner or outer * boundary). */ private int location = 0; /** Indicates that we are inside the inner boundary of the Polygon. */ private int INNER_BOUNDARY = 1; /** Indicates that we are inside the outer boundary of the Polygon. */ private int OUTER_BOUNDARY = 2; /** * Creates a new instance of GMLPolygonHandler. */ public SubHandlerPolygon() { } /** * Catches inner and outer LinearRings messages and handles them * appropriately. * * @param message Name of sub geometry located. * @param type Type of sub geometry located. */ public void subGeometry(String message, int type) { // if we have found a linear ring, either // add it to the list of inner boundaries if we are reading them // and at the end of the LinearRing // add it to the outer boundary if we are reading it and at the end of // the LinearRing // create a new linear ring, if we are at the start of a new linear ring if (message.equals("LinearRing")) { if (type == GEOMETRY_END) { if (location == INNER_BOUNDARY) { LinearRing ring = (LinearRing) currentHandler.create(geometryFactory); Coordinate[] points = ring.getCoordinates(); /* it is important later that internal rings (holes) are * anticlockwise (counter clockwise) - so we reverse the * points if necessary */ if (cga.isCCW(points)) { LOGGER.finer("good hole found"); //System.out.println("inner boundary: " + message); innerBoundaries.add(ring); } else { LOGGER.finer("bad hole found - fixing"); Coordinate[] newPoints = new Coordinate[points.length]; for (int i = 0, j = points.length - 1; i < points.length; i++, j--) { newPoints[i] = points[j]; } try { ring = geometryFactory.createLinearRing(newPoints); innerBoundaries.add(ring); } catch (TopologyException e) { LOGGER.warning( "Caught Topology exception in GMLPolygonHandler"); ring = null; } } } else if (location == OUTER_BOUNDARY) { /* it is important later that the outerboundary is * clockwise - so we reverse the * points if necessary */ outerBoundary = (LinearRing) currentHandler.create(geometryFactory); Coordinate[] points = outerBoundary.getCoordinates(); if (cga.isCCW(points)) { LOGGER.finer("bad outer ring - rebuilding"); // System.out.println("rebuilding outer ring"); Coordinate[] newPoints = new Coordinate[points.length]; for (int i = 0, j = points.length - 1; i < points.length; i++, j--) { newPoints[i] = points[j]; } try { outerBoundary = geometryFactory.createLinearRing(newPoints); //System.out.println("outer boundary: " + message); } catch (TopologyException e) { LOGGER.warning("Caught Topology exception in " + "GMLPolygonHandler"); outerBoundary = null; } } } } else if (type == GEOMETRY_START) { currentHandler = new SubHandlerLinearRing(); } } else if (message.equals("outerBoundaryIs")) { // or, if we are getting notice of an inner/outer boundary marker, // set current location appropriately LOGGER.finer("new outer Boundary"); location = OUTER_BOUNDARY; } else if (message.equals("innerBoundaryIs")) { LOGGER.finer("new InnerBoundary"); location = INNER_BOUNDARY; } } /** * Adds a coordinate to the current LinearRing. * * @param coordinate Name of sub geometry located. */ public void addCoordinate(Coordinate coordinate) { currentHandler.addCoordinate(coordinate); } /** * Determines whether or not the geometry is ready to be returned. * * @param message Name of GML element that prompted this check. * * @return Flag indicating whether or not the geometry is ready to be * returned. */ public boolean isComplete(String message) { // the conditions checked here are that the endGeometry message that // prompted this check is a Polygon and that this Polygon has an outer // boundary; if true, then return the all go signal if (message.equals("Polygon")) { if (outerBoundary != null) { return true; } else { return false; } } // otherwise, send this message to the subGeometry method for further // processing else { // this.subGeometry(message, GEOMETRY_END); return false; } } /** * Returns the completed OGC Polygon. * * @param geometryFactory Geometry factory to be used in Polygon creation. * * @return Completed OGC Polygon. */ public Geometry create(GeometryFactory geometryFactory) { for (int i = 0; i < innerBoundaries.size(); i++) { LinearRing hole = (LinearRing) innerBoundaries.get(i); if (hole.crosses(outerBoundary)) { LOGGER.warning("Topology Error building polygon"); return null; } } LinearRing[] rings = (LinearRing[]) innerBoundaries.toArray(new LinearRing[innerBoundaries.size()]); Polygon polygon = geometryFactory.createPolygon(outerBoundary,rings); polygon.setUserData( getSRS() ); polygon.setSRID( getSRID() ); return polygon; } }