//$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.digitize;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.deegree.datatypes.QualifiedName;
import org.deegree.igeo.ApplicationContainer;
import org.deegree.igeo.commands.CommandHelper;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.kernel.Command;
import org.deegree.kernel.CommandException;
import org.deegree.model.feature.Feature;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.MultiCurve;
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.Ring;
import org.deegree.model.spatialschema.Surface;
import org.deegree.model.spatialschema.SurfaceBoundary;
import org.deegree.model.spatialschema.SurfaceInterpolationImpl;
/**
* {@link Command} implementation for merging two or more vertices of a {@link Surface} or a {@link Curve} into one
* vertex
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class MergeVerticesCommand extends MoveVertexCommand {
private Envelope mergeArea;
/**
*
* @param appCont
* @param feature
* @param geomProperty
* @param targetPoint
* @param mergeArea
*/
public MergeVerticesCommand( ApplicationContainer<?> appCont, Feature feature, QualifiedName geomProperty,
Point targetPoint, Envelope mergeArea ) {
super( appCont, feature, geomProperty, targetPoint, targetPoint );
this.mergeArea = mergeArea;
name = new QualifiedName( "Merge Vertices" );
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#execute()
*/
public void execute()
throws Exception {
Iterator<Feature> iter = featureCollection.iterator();
while ( iter.hasNext() ) {
Feature feature = iter.next();
if ( geomProperty == null ) {
geomProperty = CommandHelper.findGeomProperty( feature );
}
Geometry geom = (Geometry) feature.getProperties( geomProperty )[0].getValue();
old.put( feature, geom );
boolean nearest = verticesOpt.useNearest();
if ( geom instanceof Point ) {
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$MD10319" ) );
} else if ( geom instanceof Curve ) {
geom = handleCurve( (Curve) geom, nearest );
} else if ( geom instanceof Surface ) {
geom = handleSurface( (Surface) geom, nearest );
} else if ( geom instanceof MultiPoint ) {
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$MD10321" ) );
} else if ( geom instanceof MultiCurve ) {
geom = handleMultiCurve( (MultiCurve) geom, nearest );
} else if ( geom instanceof MultiSurface ) {
geom = handleMultiSurface( (MultiSurface) geom, nearest );
}
setGeometryProperty( feature, geom );
Layer layer = appCont.getMapModel( null ).getLayersSelectedForAction( MapModel.SELECTION_EDITING ).get( 0 );
FeatureAdapter fa = (FeatureAdapter) layer.getDataAccess().get( 0 );
fa.updateFeature( feature );
}
performed = true;
fireCommandProcessedEvent();
}
private Position[] filterPositions( Position[] positions, int minPos, Position... target ) {
List<Position> posList = new ArrayList<Position>( positions.length );
int cnt = 0;
for ( int i = 0; i < positions.length; i++ ) {
if ( mergeArea.contains( positions[i] ) ) {
if ( cnt < target.length ) {
// if the first position contained within merge envelope is found set
// the target point/position instead. After this all other points contained
// within merge envelope will be ignored
posList.add( target[0] );
cnt++;
}
} else {
posList.add( positions[i] );
}
}
if ( posList.size() < minPos ) {
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$MD10315", minPos ) );
}
return posList.toArray( new Position[posList.size()] );
}
/**
*
* @param feature
* @param curve
* @param nearest
* @return
* @throws GeometryException
*/
private Geometry handleCurve( Curve curve, boolean nearest )
throws GeometryException {
Position[] positions = curve.getAsLineString().getPositions();
if ( nearest ) {
// just remove position nearest to click point
Position position = findNearest( positions );
positions = filterPositions( positions, 2, position );
} else {
positions = filterPositions( positions, 2, targetPoint.getPosition() );
}
return GeometryFactory.createCurve( positions, curve.getCoordinateSystem() );
}
/**
*
* @param geom
* @param nearest
* @return
* @throws GeometryException
*/
private Geometry handleMultiCurve( MultiCurve geom, boolean nearest )
throws GeometryException {
Curve[] curves = geom.getAllCurves();
List<Curve> curveList = new ArrayList<Curve>( curves.length );
if ( nearest ) {
// just remove position nearest nearest to clickpoint
Position[][] positions = new Position[curves.length][];
for ( int i = 0; i < curves.length; i++ ) {
positions[i] = curves[i].getAsLineString().getPositions();
}
Position[] position = findNearest( positions );
for ( int i = 0; i < positions.length; i++ ) {
positions[i] = filterPositions( positions[i], 0, position );
if ( positions[i].length > 1 ) {
curveList.add( GeometryFactory.createCurve( positions[i], geom.getCoordinateSystem() ) );
}
}
} else {
for ( Curve curve : curves ) {
Position[] positions = curve.getAsLineString().getPositions();
positions = filterPositions( positions, 0, targetPoint.getPosition() );
if ( positions.length > 1 ) {
curveList.add( GeometryFactory.createCurve( positions, geom.getCoordinateSystem() ) );
}
}
}
if ( curveList.size() == 0 ) {
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$MD10316" ) );
}
return GeometryFactory.createMultiCurve( curves );
}
/**
*
* @param geom
* @param nearest
* @return
* @throws GeometryException
*/
private Geometry handleMultiSurface( MultiSurface geom, boolean nearest )
throws GeometryException {
Surface[] surfaces = geom.getAllSurfaces();
List<Surface> surfaceList = new ArrayList<Surface>( surfaces.length );
if ( nearest ) {
// just move position nearest to click point
// find nearest position
List<Position[]> list = new ArrayList<Position[]>();
for ( Surface surface : surfaces ) {
SurfaceBoundary sb = surface.getSurfaceBoundary();
Ring[] inner = sb.getInteriorRings();
list.add( sb.getExteriorRing().getPositions() );
for ( int i = 0; i < inner.length; i++ ) {
list.add( inner[i].getPositions() );
}
}
Position[][] positions = list.toArray( new Position[list.size()][] );
Position[] position = findNearest( positions );
// delete nearest position
for ( Surface surface : surfaces ) {
SurfaceBoundary sb = surface.getSurfaceBoundary();
Position[] ext = sb.getExteriorRing().getPositions();
ext = validateRing( filterPositions( ext, 4, position ) );
Ring[] inner = sb.getInteriorRings();
List<Position[]> innerList = new ArrayList<Position[]>( inner.length );
for ( Ring ring : inner ) {
Position[] in = ring.getPositions();
in = filterPositions( in, 0, position );
if ( in.length > 3 ) {
innerList.add( validateRing( in ) );
}
}
Position[][] innerPos = innerList.toArray( new Position[innerList.size()][] );
surfaceList.add( GeometryFactory.createSurface( ext, innerPos, new SurfaceInterpolationImpl(),
surface.getCoordinateSystem() ) );
}
} else {
for ( Surface surface : surfaces ) {
surfaceList.add( (Surface) handleSurface( surface, false ) );
}
}
if ( surfaceList.size() == 0 ) {
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$MD10318" ) );
}
return GeometryFactory.createMultiSurface( surfaces );
}
/**
*
* @param surface
* @param nearest
* @return
* @throws GeometryException
*/
private Geometry handleSurface( Surface surface, boolean nearest )
throws GeometryException {
SurfaceBoundary sb = surface.getSurfaceBoundary();
Position[] ext = sb.getExteriorRing().getPositions();
Ring[] inner = sb.getInteriorRings();
List<Position[]> innerList = new ArrayList<Position[]>( inner.length );
if ( nearest ) {
// just add external ring for searching nearest position
innerList.add( ext );
for ( Ring ring : inner ) {
Position[] in = ring.getPositions();
innerList.add( in );
}
Position[][] tmp = innerList.toArray( new Position[innerList.size()][] );
Position[] position = findNearest( tmp );
ext = validateRing( filterPositions( tmp[0], 4, position ) );
innerList.clear();
for ( int i = 1; i < tmp.length; i++ ) {
Position[] in = filterPositions( tmp[i], 0, position );
if ( in.length > 3 ) {
innerList.add( validateRing( in ) );
}
}
} else {
ext = validateRing( filterPositions( ext, 4, targetPoint.getPosition() ) );
for ( Ring ring : inner ) {
Position[] in = ring.getPositions();
in = filterPositions( in, 0, targetPoint.getPosition() );
if ( in.length > 3 ) {
innerList.add( validateRing( in ) );
}
}
}
Position[][] innerPos = innerList.toArray( new Position[innerList.size()][] );
return GeometryFactory.createSurface( ext, innerPos, new SurfaceInterpolationImpl(),
surface.getCoordinateSystem() );
}
}