//$HeadURL$
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2008 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.igeo.commands.geoprocessing;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.deegree.datatypes.QualifiedName;
import org.deegree.datatypes.Types;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.igeo.commands.model.AddErrorLayerCommand;
import org.deegree.igeo.dataadapter.DataAccessAdapter;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.WFSDatasource;
import org.deegree.igeo.settings.ValidationGeomMetrics;
import org.deegree.igeo.settings.ValidationGeomTopology;
import org.deegree.igeo.settings.ValidationGeomTypes;
import org.deegree.kernel.Command;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.schema.PropertyType;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.JTSAdapter;
import org.deegree.model.spatialschema.MultiCurve;
import org.deegree.model.spatialschema.MultiGeometry;
import org.deegree.model.spatialschema.MultiPoint;
import org.deegree.model.spatialschema.MultiSurface;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Position;
import org.deegree.model.spatialschema.Surface;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Command class for validating a layer considerung current configuration settings. A layer will be validated for
* presents of not allowed geometry types and for topological releations between geometries. Additionally each geometry
* will be validated if it is valid itself. Checking geometry validity will be done as describe for
* {@link ValidateGeometriesCommand}
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class ValidateLayer4GeometriesCommand extends ValidateGeometriesCommand {
private static final ILogger LOG = LoggerFactory.getLogger( ValidateLayer4GeometriesCommand.class );
private static final QualifiedName name = new QualifiedName( "Validate layer for geometries" );
/**
* @param layer
* @param geometries
*/
public ValidateLayer4GeometriesCommand( Layer layer, List<Geometry> geometries ) {
super( layer, geometries );
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#execute()
*/
public void execute()
throws Exception {
try {
errorCount = 0;
List<DataAccessAdapter> daaList = layer.getDataAccess();
int max = 0;
for ( DataAccessAdapter adapter : daaList ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureCollection fc = ( (FeatureAdapter) adapter ).getFeatureCollection();
max += fc.size();
}
}
if ( processMonitor != null ) {
processMonitor.setMaximumValue( ( max - 1 ) * 2 );
}
for ( DataAccessAdapter adapter : daaList ) {
if ( adapter instanceof FeatureAdapter ) {
LOG.logDebug( "validating datasource: ", adapter.getDatasource().getName() );
FeatureCollection fc = ( (FeatureAdapter) adapter ).getFeatureCollection();
performGeometryValidation( adapter, fc );
performTopologicalValidation( adapter, fc );
}
}
if ( errorCount > 0 ) {
errorReport.put( "errorCount", Integer.toString( errorCount ) );
Command cmd = new AddErrorLayerCommand( layer.getOwner().getApplicationContainer(), layer,
errorPositions );
layer.getOwner().getApplicationContainer().getCommandProcessor().executeSychronously( cmd, true );
}
} catch ( Exception e ) {
throw e;
} finally {
if ( processMonitor != null ) {
processMonitor.cancel();
}
}
fireCommandProcessedEvent();
}
private void performTopologicalValidation( DataAccessAdapter adapter, FeatureCollection fc )
throws GeometryException {
LOG.logDebug( "start topological validation" );
ValidationGeomTopology vgt = settings.getValidationGeomTopology();
QualifiedName geomProperty = findGeomProperty( (FeatureAdapter) adapter, fc );
if ( geomProperty != null ) {
int cnt = fc.size();
for ( int i = 0; i < cnt; i++ ) {
if ( processMonitor != null ) {
processMonitor.updateStatus( cnt + i - 1, "" );
}
Feature feature = fc.getFeature( i );
Geometry g1 = (Geometry) feature.getProperties( geomProperty )[0].getValue();
com.vividsolutions.jts.geom.Geometry jtsG1 = JTSAdapter.export( g1 );
for ( int j = i + 1; j < cnt; j++ ) {
feature = fc.getFeature( j );
Geometry g2 = (Geometry) feature.getProperties( geomProperty )[0].getValue();
com.vividsolutions.jts.geom.Geometry jtsG2 = JTSAdapter.export( g2 );
if ( !vgt.intersectionAllowed() ) {
try {
if ( jtsG1.intersects( jtsG2 ) && !jtsG1.touches( jtsG2 ) ) {
errorReport.put( "allowIntersection_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10451", i, j ) );
addErrorPosition( g1.getCentroid().getPosition(),
Messages.getMessage( Locale.getDefault(), "$MD10451", i, j ) );
}
} catch ( Exception e ) {
errorReport.put( "allowIntersection_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10451", i, j ) );
addErrorPosition( g1.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10451", i, j ) );
}
}
if ( !vgt.touchingAllowed() ) {
try {
if ( jtsG1.touches( jtsG2 ) ) {
errorReport.put( "allowTouching_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10452", i, j ) );
}
addErrorPosition( g1.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10452", i, j ) );
} catch ( Exception e ) {
errorReport.put( "allowTouching_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10452", i, j ) );
addErrorPosition( g1.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10452", i, j ) );
}
}
if ( !vgt.equalGeometriesAllowed() ) {
try {
if ( jtsG1.equals( jtsG2 ) ) {
errorReport.put( "allowEqualGeometries_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10453", i, j ) );
addErrorPosition( g1.getCentroid().getPosition(),
Messages.getMessage( Locale.getDefault(), "$MD10453", i, j ) );
}
} catch ( Exception e ) {
errorReport.put( "allowEqualGeometries_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10453", i, j ) );
addErrorPosition( g1.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10453", i, j ) );
}
}
}
}
}
}
private void performGeometryValidation( DataAccessAdapter adapter, FeatureCollection fc )
throws GeometryException {
LOG.logDebug( "start geometric validation" );
ValidationGeomTypes vgt = settings.getValidationGeomTypes();
ValidationGeomMetrics vgm = settings.getValidationGeomMetrics();
float minDist = vgm.getMinSegmentLength();
float minArea = vgm.getMinPolygonArea();
Iterator<Feature> iterator = fc.iterator();
QualifiedName geomProperty = findGeomProperty( (FeatureAdapter) adapter, fc );
if ( geomProperty != null ) {
int i = -1;
while ( iterator.hasNext() ) {
i++;
if ( processMonitor != null ) {
processMonitor.updateStatus( i, "" );
}
Feature feature = iterator.next();
Geometry geometry = (Geometry) feature.getProperties( geomProperty )[0].getValue();
com.vividsolutions.jts.geom.Geometry jtsGeom = JTSAdapter.export( geometry );
if ( vgm.checkForValidGeometries() && !jtsGeom.isValid() ) {
addErrorPosition( geometry.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10426", i ) );
errorReport.put( "checkForValidGeometries_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10426", i ) );
}
if ( vgm.disallowRepeatedPoints() && rpTester.hasRepeatedPoint( jtsGeom ) ) {
Coordinate c = rpTester.getCoordinate();
Position p = GeometryFactory.createPosition( c.x, c.y );
addErrorPosition( p, Messages.getMessage( Locale.getDefault(), "$MD10427", i ) );
errorReport.put( "disallowRepeatedPoints_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10427", i ) );
}
if ( vgm.checkForPolygonOrientation() ) {
handleCheckForPolygonOrientation( jtsGeom, i );
}
if ( vgm.disallowDoubleGeomerties() ) {
handleDisallowDoubleGeomerties( geometry, i );
}
if ( vgm.ensureSimpleLines() ) {
handleSimpleLines( geometry, jtsGeom, i );
}
if ( vgm.limitMinSegmentLength() ) {
handleMinSegmentLength( geometry, i, minDist );
}
if ( vgm.limitMinPolygonArea() ) {
handleMinPolygonArea( geometry, i, minArea );
}
if ( !vgt.pointsAllowed() && geometry instanceof Point ) {
addErrorPosition( geometry.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10443", i ) );
errorReport.put( "allowPoints_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10443", i ) );
}
if ( !vgt.linestringsAllowed() && geometry instanceof Curve ) {
addErrorPosition( geometry.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10444", i ) );
errorReport.put( "allowLinestrings_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10444", i ) );
}
if ( !vgt.polygonsAllowed() && geometry instanceof Surface ) {
addErrorPosition( geometry.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10444", i ) );
errorReport.put( "allowPolygons_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10445", i ) );
}
if ( !vgt.multiPointsAllowed() && geometry instanceof MultiPoint ) {
Point[] pos = ( (MultiPoint) geometry ).getAllPoints();
for ( Point point : pos ) {
addErrorPosition( point.getPosition(), Messages.getMessage( Locale.getDefault(), "$MD10444", i ) );
}
errorReport.put( "allowMultiPoints_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10446", i ) );
}
if ( !vgt.multiLinestringsAllowed() && geometry instanceof MultiCurve ) {
Curve[] curves = ( (MultiCurve) geometry ).getAllCurves();
for ( Curve curve : curves ) {
addErrorPosition( curve.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10444", i ) );
}
errorReport.put( "allowMultiLinestrings_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10447", i ) );
}
if ( !vgt.multiPolygonsAllowed() && geometry instanceof MultiSurface ) {
Surface[] surfaces = ( (MultiSurface) geometry ).getAllSurfaces();
for ( Surface surface : surfaces ) {
addErrorPosition( surface.getCentroid().getPosition(),
Messages.getMessage( Locale.getDefault(), "$MD10444", i ) );
}
errorReport.put( "allowMultiPolygons_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10448", i ) );
}
if ( !vgt.geometryCollectionsAllowed() && geometry instanceof MultiGeometry ) {
errorReport.put( "allowGeometryCollections_" + ( errorCount++ ),
Messages.getMessage( Locale.getDefault(), "$MD10449", i ) );
}
if ( !vgt.polygonsWithHolesAllowed() ) {
handleAllowHoles( geometry, i );
}
if ( !vgt.noneLinearInterpolationAllowed() ) {
// TODO
LOG.logWarning( "check for noneLinearInterpolationAllowed is not supported yet" );
}
}
}
}
private void handleAllowHoles( Geometry geometry, int index ) {
if ( geometry instanceof Surface ) {
Surface surface = (Surface) geometry;
if ( surface.getSurfaceBoundary().getInteriorRings().length > 0 ) {
addErrorPosition( surface.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10450", index ) );
errorReport.put( "allowHoles_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10450", index ) );
}
} else if ( geometry instanceof MultiSurface ) {
Surface[] surfaces = ( (MultiSurface) geometry ).getAllSurfaces();
for ( Surface surface : surfaces ) {
if ( surface.getSurfaceBoundary().getInteriorRings().length > 0 ) {
addErrorPosition( surface.getCentroid().getPosition(), Messages.getMessage( Locale.getDefault(),
"$MD10450", index ) );
errorReport.put( "allowHoles_" + ( errorCount++ ), Messages.getMessage( Locale.getDefault(),
"$MD10450", index ) );
}
}
}
}
/**
*
* @return name of the first geometry property found or <code>null</code> if feature does not contains a geometry
* property
*/
protected QualifiedName findGeomProperty( FeatureAdapter adapter, FeatureCollection fc ) {
if ( adapter.getDatasource() instanceof WFSDatasource ) {
return ( (WFSDatasource) adapter.getDatasource() ).getGeometryProperty();
} else {
Feature feature = fc.getFeature( 0 );
PropertyType[] pt = feature.getFeatureType().getProperties();
for ( PropertyType type : pt ) {
if ( type.getType() == Types.GEOMETRY ) {
return type.getName();
}
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#getName()
*/
public QualifiedName getName() {
return name;
}
}