diff --git a/deegree-core/deegree-core-base/src/test/java/org/deegree/geometry/validation/GeometryValidatorTest.java b/deegree-core/deegree-core-base/src/test/java/org/deegree/geometry/validation/GeometryValidatorTest.java index 6b3c8c2c80..47e962f259 100644 --- a/deegree-core/deegree-core-base/src/test/java/org/deegree/geometry/validation/GeometryValidatorTest.java +++ b/deegree-core/deegree-core-base/src/test/java/org/deegree/geometry/validation/GeometryValidatorTest.java @@ -49,7 +49,9 @@ import junit.framework.Assert; import org.deegree.commons.xml.XMLParsingException; +import org.deegree.cs.coordinatesystems.ICRS; import org.deegree.cs.exceptions.UnknownCRSException; +import org.deegree.cs.persistence.CRSManager; import org.deegree.geometry.Geometry; import org.deegree.geometry.validation.event.CurveDiscontinuity; import org.deegree.geometry.validation.event.CurveSelfIntersection; @@ -160,6 +162,38 @@ public void validatePolygon() Assert.assertTrue( ( (InteriorRingOrientation) eventHandler.getEvents().get( 2 ) ).isClockwise() ); } + @Test + public void validatePolygonExteriorAndInterior() + throws XMLStreamException, FactoryConfigurationError, IOException, XMLParsingException, + UnknownCRSException { + DummyValidationEventHandler eventHandler = new DummyValidationEventHandler(); + GeometryValidator validator = new GeometryValidator( eventHandler ); + Geometry geom = parseGeometry( "Polygon.gml" ); + Assert.assertTrue( validator.validateGeometry( geom ) ); + Assert.assertEquals( 3, eventHandler.getEvents().size() ); + + // get rings + ExteriorRingOrientation exterior = (ExteriorRingOrientation) eventHandler.getEvents().get( 0 ); + InteriorRingOrientation interior1 = (InteriorRingOrientation) eventHandler.getEvents().get( 1 ); + InteriorRingOrientation interior2 = (InteriorRingOrientation) eventHandler.getEvents().get( 2 ); + + // check for exterior and interior rings with a right handed CRS + Assert.assertTrue( exterior.isExterior() ); + Assert.assertTrue( interior1.isInterior() ); + Assert.assertTrue( interior2.isInterior() ); + + // substitute original right handed CRS for a new left handed one, maintaining polygon orientation + ICRS leftHandedCrs = CRSManager.getCRSRef( "urn:ogc:def:crs:epsg::4326" ); + exterior.getPatch().getExteriorRing().setCoordinateSystem( leftHandedCrs ); + interior1.getPatch().getInteriorRings().get( 0 ).setCoordinateSystem( leftHandedCrs ); + interior2.getPatch().getInteriorRings().get( 1 ).setCoordinateSystem( leftHandedCrs ); + + // check for exterior and interior rings with a left handed CRS + Assert.assertFalse( exterior.isExterior() ); + Assert.assertFalse( interior1.isInterior() ); + Assert.assertFalse( interior2.isInterior() ); + } + @Test public void validatePolygonExteriorClockwise() throws XMLStreamException, FactoryConfigurationError, IOException, XMLParsingException, diff --git a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/AbstractGeometryValidationEvent.java b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/AbstractGeometryValidationEvent.java index b514254164..dd1e8830bb 100644 --- a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/AbstractGeometryValidationEvent.java +++ b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/AbstractGeometryValidationEvent.java @@ -37,6 +37,9 @@ import java.util.List; +import org.deegree.cs.coordinatesystems.ICRS; +import org.deegree.cs.components.Axis; + /** * Abstract base class for {@link GeometryValidationEvent} implementations. * @@ -65,4 +68,38 @@ public List getGeometryParticleHierarchy() { return geometryParticleHierachy; } + /** + * Returns true if the geometry has a left handed CRS. + * + * @return true if geometry has a left handed CRS, false if CRS is right handed + */ + protected boolean isLeftHanded( ICRS crs ) { + // get number of dimensions (it should be 2) + if ( crs.getDimension() == 2 ) { + int axis1 = crs.getAxis()[0].getOrientation(); + int axis2 = crs.getAxis()[1].getOrientation(); + + // check if CRS is left handed + if ( axis1 == Axis.AO_EAST || axis1 == Axis.AO_WEST ) { + if ( axis1 == Axis.AO_EAST && ( axis2 == Axis.AO_SOUTH || axis2 == Axis.AO_DOWN ) ) { + return true; + } + else if ( axis1 == Axis.AO_WEST && ( axis2 == Axis.AO_NORTH || axis2 == Axis.AO_UP ) ) { + return true; + } + } + else { + if ( ( axis1 == Axis.AO_SOUTH || axis1 == Axis.AO_DOWN ) && axis2 == Axis.AO_WEST ) { + return true; + } + else if ( ( axis1 == Axis.AO_NORTH || axis1 == Axis.AO_UP ) && axis2 == Axis.AO_EAST ) { + return true; + } + } + } + + // return false in any other case + return false; + } + } diff --git a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/ExteriorRingOrientation.java b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/ExteriorRingOrientation.java index 0af1c350a1..675021a862 100644 --- a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/ExteriorRingOrientation.java +++ b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/ExteriorRingOrientation.java @@ -88,4 +88,19 @@ public boolean isClockwise() { return isClockwise; } + /** + * Returns true if the geometry is an exterior boundary. + * + * @return true if geometry is an exterior boundary, false if it's interior + */ + public boolean isExterior() { + boolean isExterior = !isClockwise; + + if ( isLeftHanded( patch.getExteriorRing().getCoordinateSystem() ) ) { + isExterior = !isExterior; + } + + return isExterior; + } + } diff --git a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/InteriorRingOrientation.java b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/InteriorRingOrientation.java index a3a051caa1..b32528e5d8 100644 --- a/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/InteriorRingOrientation.java +++ b/deegree-core/deegree-core-geometry/src/main/java/org/deegree/geometry/validation/event/InteriorRingOrientation.java @@ -103,4 +103,19 @@ public boolean isClockwise() { return isClockwise; } + /** + * Returns true if the geometry is an interior boundary. + * + * @return true if geometry is an interior boundary, false if it's exterior + */ + public boolean isInterior() { + boolean isInterior = isClockwise; + + if ( isLeftHanded( patch.getInteriorRings().get( ringIdx ).getCoordinateSystem() ) ) { + isInterior = !isInterior; + } + + return isInterior; + } + }