//$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 static java.util.Collections.singletonList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.util.Pair;
import org.deegree.igeo.ApplicationContainer;
import org.deegree.igeo.commands.CommandHelper;
import org.deegree.igeo.commands.model.AddErrorLayerCommand;
import org.deegree.igeo.config.LayerType.MetadataURL;
import org.deegree.igeo.dataadapter.DataAccessAdapter;
import org.deegree.igeo.dataadapter.DataAccessFactory;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.mapmodel.Datasource;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.kernel.AbstractCommand;
import org.deegree.kernel.Command;
import org.deegree.model.Identifier;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureFactory;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Position;
/**
* {@link Command} implementation for finding/creating intersections between geometries contained in one or two layers.
* The result will be added as new layer
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
*
* @author last edited by: $Author$
*
* @version $Revision$, $Date$
*
*/
public class LayerIntersectionCommand extends AbstractCommand {
public static final QualifiedName name = new QualifiedName( "Layer Intersection" );
public enum INTERSECTION_TYPE {
Intersection, Union, Difference, SymmetricDifference
};
private Layer mainLayer;
private QualifiedName mainGeom;
private Layer compareLayer;
private QualifiedName compGeom;
private String newLayerName;
private Layer newLayer;
private INTERSECTION_TYPE intersectiontype = INTERSECTION_TYPE.Intersection;
private boolean performed;
/**
*
* @param mainLayer
* layer that will be used to create alpha numeric properties for new layer
* @param compareLayer
* @param newLayerName
* name of the new layer
*/
public LayerIntersectionCommand( Layer mainLayer, Layer compareLayer, String newLayerName ) {
this.mainLayer = mainLayer;
this.compareLayer = compareLayer;
this.newLayerName = newLayerName;
}
/**
*
* @param mainLayer
* layer that will be used to create alpha numeric properties for new layer
* @param compareLayer
* @param newLayerName
* name of the new layer
* @param intersectiontype
*/
public LayerIntersectionCommand( Layer mainLayer, Layer compareLayer,
String newLayerName, INTERSECTION_TYPE intersectiontype ) {
this.mainLayer = mainLayer;
this.compareLayer = compareLayer;
this.newLayerName = newLayerName;
if ( intersectiontype != null ) {
this.intersectiontype = intersectiontype;
}
}
/**
*
* @throws Exception
*/
public void execute()
throws Exception {
performed = false;
try {
FeatureCollection mainFC = getMainFeatures();
FeatureCollection compareFC = getCompareFeatures();
FeatureCollection resultFC = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(),
mainFC.size() + compareFC.size() );
mainGeom = CommandHelper.findGeomProperty( mainFC.getFeature( 0 ) );
compGeom = CommandHelper.findGeomProperty( compareFC.getFeature( 0 ) );
// calculate intersection between each geometry of main layer with each geometry of comparing layer
// if an intersection is not null; the result geometry will be used to create a new feature filled
// with alpha numeric properties of the source feature from main layer
List<Position> posList = new ArrayList<Position>();
switch ( intersectiontype ) {
case Intersection:
handleIntersection( mainFC, compareFC, resultFC, posList );
break;
case Union:
handleUnion( mainFC, compareFC, resultFC );
break;
case Difference:
handleDifference( mainFC, compareFC, resultFC, posList );
break;
case SymmetricDifference:
handleSymmetricDifference( mainFC, compareFC, resultFC, posList );
break;
}
Datasource ds = DataAccessFactory.createDatasource( newLayerName, resultFC );
MapModel mm = mainLayer.getOwner();
Identifier id = new Identifier( newLayerName );
int i = 0;
while ( mm.exists( id ) ) {
id = new Identifier( newLayerName + "_" + i++ );
}
newLayer = new Layer( mm, id, id.getValue(), newLayerName, singletonList( ds ),
Collections.<MetadataURL> emptyList() );
newLayer.setEditable( true );
mm.insert( newLayer, mainLayer.getParent(), mainLayer, false );
if ( posList.size() > 0 ) {
createErrorlayer( "intersection error", posList );
}
} catch ( Exception e ) {
e.printStackTrace();
throw e;
} finally {
if ( processMonitor != null ) {
processMonitor.cancel();
}
}
performed = true;
}
/**
* @param mainFC
* @param compareFC
* @param resultFC
* @param posList
* @throws CloneNotSupportedException
*/
private void handleSymmetricDifference( FeatureCollection mainFC, FeatureCollection compareFC,
FeatureCollection resultFC, List<Position> posList )
throws CloneNotSupportedException {
FeatureCollection tmpFC1 = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(),
mainFC.size() + compareFC.size() );
FeatureCollection tmpFC2 = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(),
mainFC.size() + compareFC.size() );
handleUnion( mainFC, compareFC, tmpFC1 );
if ( processMonitor != null ) {
// reset
}
handleIntersection( mainFC, compareFC, tmpFC2, posList );
if ( processMonitor != null ) {
// reset
}
handleDifference( tmpFC1, tmpFC2, resultFC, posList );
}
/**
* @param mainFC
* @param compareFC
* @param resultFC
* @param posList
* @throws CloneNotSupportedException
*/
private void handleDifference( FeatureCollection mainFC, FeatureCollection compareFC, FeatureCollection resultFC,
List<Position> posList )
throws CloneNotSupportedException {
if ( processMonitor != null ) {
processMonitor.setMaximumValue( mainFC.size() + compareFC.size() );
}
Iterator<Feature> iterator = mainFC.iterator();
int cnt = 0;
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
Geometry mainG = (Geometry) feature.getDefaultProperty( mainGeom ).getValue();
Iterator<Feature> compare = compareFC.iterator();
while ( compare.hasNext() ) {
if ( processMonitor != null ) {
processMonitor.updateStatus( cnt++, "" );
}
Feature compFeature = (Feature) compare.next();
Geometry compG = (Geometry) compFeature.getDefaultProperty( compGeom ).getValue();
try {
if ( compG != null && mainG != null ) {
mainG = mainG.difference( compG );
}
} catch ( Exception e ) {
if ( mainG != null && compG != null ) {
posList.add( mainG.getCentroid().getPosition() );
posList.add( compG.getCentroid().getPosition() );
}
}
}
if ( mainG != null ) {
Feature feat = feature.cloneDeep();
feat.getDefaultProperty( mainGeom ).setValue( mainG );
resultFC.add( feat );
}
}
}
/**
* @param mainFC
* @param compareFC
* @param resultFC
* @throws CloneNotSupportedException
*/
private void handleUnion( FeatureCollection mainFC, FeatureCollection compareFC, FeatureCollection resultFC )
throws CloneNotSupportedException {
if ( processMonitor != null ) {
processMonitor.setMaximumValue( mainFC.size() + compareFC.size() );
}
int cnt = 0;
Iterator<Feature> iterator = mainFC.iterator();
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
feature = feature.cloneDeep();
resultFC.add( feature );
if ( processMonitor != null ) {
processMonitor.updateStatus( cnt++, "" );
}
}
iterator = compareFC.iterator();
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
feature = feature.cloneDeep();
resultFC.add( feature );
if ( processMonitor != null ) {
processMonitor.updateStatus( cnt++, "" );
}
}
}
private void handleIntersection( FeatureCollection mainFC, FeatureCollection compareFC, FeatureCollection resultFC,
List<Position> posList )
throws CloneNotSupportedException {
if ( processMonitor != null ) {
processMonitor.setMaximumValue( mainFC.size() * compareFC.size() );
}
int cnt = 0;
Iterator<Feature> iterator = mainFC.iterator();
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
Geometry mainG = (Geometry) feature.getDefaultProperty( mainGeom ).getValue();
Iterator<Feature> compare = compareFC.iterator();
while ( compare.hasNext() ) {
if ( processMonitor != null ) {
processMonitor.updateStatus( cnt++, "" );
}
Feature compFeature = (Feature) compare.next();
if ( !compFeature.getId().equals( feature.getId() ) ) {
Geometry compG = (Geometry) compFeature.getDefaultProperty( compGeom ).getValue();
Geometry tmp = null;
try {
tmp = mainG.intersection( compG );
} catch ( Exception e ) {
posList.add( mainG.getCentroid().getPosition() );
posList.add( compG.getCentroid().getPosition() );
}
if ( tmp != null ) {
Feature feat = feature.cloneDeep();
feat.getDefaultProperty( mainGeom ).setValue( tmp );
resultFC.add( feat );
}
}
}
}
}
private void createErrorlayer( String message, List<Position> posList )
throws Exception {
MapModel mapModel = mainLayer.getOwner();
ApplicationContainer<?> appCont = mapModel.getApplicationContainer();
List<Pair<String, Point>> errorLocations = new ArrayList<Pair<String, Point>>( posList.size() );
for ( Position position : posList ) {
Pair<String, Point> pa = new Pair<String, Point>();
pa.first = message;
pa.second = GeometryFactory.createPoint( position, mapModel.getCoordinateSystem() );
errorLocations.add( pa );
}
Command cmd = new AddErrorLayerCommand( appCont, mainLayer, errorLocations );
appCont.getCommandProcessor().executeSychronously( cmd, true );
}
private FeatureCollection getCompareFeatures() {
FeatureCollection compareFC = compareLayer.getSelectedFeatures();
if ( compareFC.size() == 0 ) {
List<DataAccessAdapter> dataAdapters = compareLayer.getDataAccess();
for ( DataAccessAdapter dataAccessAdapter : dataAdapters ) {
if ( dataAccessAdapter instanceof FeatureAdapter ) {
FeatureCollection fc = ( (FeatureAdapter) dataAccessAdapter ).getFeatureCollection();
Iterator<Feature> iterator = fc.iterator();
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
compareFC.add( feature );
}
}
}
}
return compareFC;
}
private FeatureCollection getMainFeatures() {
FeatureCollection mainFC = mainLayer.getSelectedFeatures();
if ( mainFC.size() == 0 ) {
List<DataAccessAdapter> dataAdapters = mainLayer.getDataAccess();
for ( DataAccessAdapter dataAccessAdapter : dataAdapters ) {
if ( dataAccessAdapter instanceof FeatureAdapter ) {
FeatureCollection fc = ( (FeatureAdapter) dataAccessAdapter ).getFeatureCollection();
Iterator<Feature> iterator = fc.iterator();
while ( iterator.hasNext() ) {
Feature feature = (Feature) iterator.next();
mainFC.add( feature );
}
}
}
}
return mainFC;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#getName()
*/
public QualifiedName getName() {
return name;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#getResult()
*/
public Object getResult() {
return newLayer;
}
@Override
public boolean isUndoSupported() {
return true;
}
@Override
public void undo()
throws Exception {
if ( performed ) {
newLayer.getOwner().remove( newLayer );
performed = false;
}
}
}