//$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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.util.GeometryUtils;
import org.deegree.igeo.ApplicationContainer;
import org.deegree.igeo.commands.CommandHelper;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.igeo.settings.DigitizingVerticesOpt;
import org.deegree.kernel.AbstractCommand;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureFactory;
import org.deegree.model.feature.FeatureProperty;
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.GeometryImpl;
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;
/**
* Command class for moving a or a group of vertexes belonging to one or more features/geometries
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class MoveVertexCommand extends AbstractCommand {
protected QualifiedName name = new QualifiedName( "Move Vertex" );
protected boolean performed = false;
protected FeatureCollection featureCollection;
protected Point sourcePoint;
protected Point targetPoint;
protected QualifiedName geomProperty;
protected Map<Feature, Geometry> old = new HashMap<Feature, Geometry>();
protected DigitizingVerticesOpt verticesOpt;
protected ApplicationContainer<?> appCont;
/**
*
* @param verticesOpt
* @param feature
* @param geomProperty
* @param sourcePoint
* @param targetPoint
*/
public MoveVertexCommand( ApplicationContainer<?> appCont, Feature feature, QualifiedName geomProperty,
Point sourcePoint, Point targetPoint ) {
if ( feature instanceof FeatureCollection ) {
this.featureCollection = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(),
( (FeatureCollection) feature ).size() );
this.featureCollection.addAllUncontained( (FeatureCollection) feature );
} else {
this.featureCollection = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(),
new Feature[] { feature } );
}
this.appCont = appCont;
this.verticesOpt = appCont.getSettings().getDigitizingVerticesOptions();
this.sourcePoint = sourcePoint;
this.targetPoint = targetPoint;
this.geomProperty = geomProperty;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#execute()
*/
public void execute()
throws Exception {
double dx = targetPoint.getX() - sourcePoint.getX();
double dy = targetPoint.getY() - sourcePoint.getY();
double[] dxy = new double[] { dx, dy };
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();
Geometry tmpGeom = (Geometry) ( (GeometryImpl) geom ).clone();
old.put( feature, tmpGeom );
boolean nearest = verticesOpt.handleNearest();
if ( geom instanceof Point ) {
handlePoint( dxy, geom );
} else if ( geom instanceof Curve ) {
handleCurve( dxy, (Curve) geom, nearest );
} else if ( geom instanceof Surface ) {
handleSurface( dxy, (Surface) geom, nearest );
} else if ( geom instanceof MultiPoint ) {
handleMultiPoint( dxy, (MultiPoint) geom, nearest );
} else if ( geom instanceof MultiCurve ) {
handleMultiCurve( dxy, (MultiCurve) geom, nearest );
} else if ( geom instanceof MultiSurface ) {
handleMultiSurface( dxy, (MultiSurface) geom, nearest );
}
Layer layer = appCont.getMapModel( null ).getLayersSelectedForAction( MapModel.SELECTION_EDITING ).get( 0 );
FeatureAdapter fa = (FeatureAdapter) layer.getDataAccess().get( 0 );
fa.updateFeature( feature );
}
performed = true;
fireCommandProcessedEvent();
}
/**
*
* @param allPoints
* @return {@link Point} nearest to click point
*/
protected Point findNearest( Point[] allPoints ) {
double tolerance = sourcePoint.getTolerance();
Point result = null;
double dist = Double.MAX_VALUE;
for ( Point point : allPoints ) {
double tmp = GeometryUtils.distance( sourcePoint.getPosition(), point.getPosition() );
if ( tmp < dist && tmp <= tolerance ) {
dist = tmp;
result = point;
}
}
return result;
}
/**
*
* @param positions
* @return {@link Position} nearest to click point
*/
protected Position findNearest( Position[] positions ) {
double tolerance = sourcePoint.getTolerance();
Position result = null;
double dist = Double.MAX_VALUE;
for ( Position position : positions ) {
double tmp = GeometryUtils.distance( sourcePoint.getPosition(), position );
if ( tmp < dist && tmp <= tolerance ) {
dist = tmp;
result = position;
}
}
return result;
}
/**
*
* @param positions
* @return {@link Position} nearest to click point
*/
protected Position[] findNearest( Position[][] positions ) {
double tolerance = sourcePoint.getTolerance();
Position result = null;
double dist = Double.MAX_VALUE;
int outIndex = 0;
int index = 0;
for ( int i = 0; i < positions.length; i++ ) {
for ( int j = 0; j < positions[i].length; j++ ) {
double tmp = GeometryUtils.distance( sourcePoint.getPosition(), positions[i][j] );
if ( tmp < dist && tmp <= tolerance ) {
dist = tmp;
result = positions[i][j];
index = j;
outIndex = i;
}
}
}
if ( index == 0 || positions[outIndex].length == index + 1 ) {
return new Position[] { result, positions[outIndex][positions[outIndex].length - 1] };
}
return new Position[] { result };
}
private void handleMultiPoint( double[] dxy, MultiPoint geom, boolean nearest ) {
Point[] points = geom.getAllPoints();
if ( nearest ) {
// just move position nearest to click point
Point point = findNearest( points );
point.translate( dxy );
} else {
for ( Point point : points ) {
point.translate( dxy );
}
}
}
private void handleMultiSurface( double[] dxy, MultiSurface geom, boolean nearest ) {
Surface[] surfaces = geom.getAllSurfaces();
if ( nearest ) {
// just move position nearest to click point
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 );
for ( int i = 0; i < position.length; i++ ) {
position[i].translate( dxy );
}
} else {
for ( Surface surface : surfaces ) {
handleSurface( dxy, surface, false );
}
}
}
private void handleMultiCurve( double[] dxy, MultiCurve geom, boolean nearest )
throws GeometryException {
Curve[] curves = geom.getAllCurves();
if ( nearest ) {
// just move position nearest to click point
Position[][] positions = new Position[curves.length][];
for ( int i = 0; i < curves.length; i++ ) {
positions[i] = curves[i].getAsLineString().getPositions();
}
Position[] position = findNearest( positions );
position[0].translate( dxy );
} else {
for ( Curve curve : curves ) {
handleCurve( dxy, curve, false );
}
}
}
private void handlePoint( double[] dxy, Geometry geom ) {
( (Point) geom ).translate( dxy );
}
/**
*
* @param dxy
* @param curve
* @param nearest
* @throws GeometryException
*/
private void handleCurve( double[] dxy, Curve curve, boolean nearest )
throws GeometryException {
Position[] positions = curve.getAsLineString().getPositions();
if ( nearest ) {
// just move position nearest to click point
Position position = findNearest( positions );
position.translate( dxy );
} else {
moveVertex( positions, dxy );
}
}
/**
*
* @param dxy
* @param surface
*/
private void handleSurface( double[] dxy, Surface surface, boolean nearest ) {
SurfaceBoundary sb = surface.getSurfaceBoundary();
if ( nearest ) {
// just move position nearest to click point
Ring[] inner = sb.getInteriorRings();
Position[][] positions = new Position[inner.length + 1][];
positions[0] = sb.getExteriorRing().getPositions();
for ( int i = 1; i < positions.length; i++ ) {
positions[i] = inner[i - 1].getPositions();
}
Position[] position = findNearest( positions );
for ( int i = 0; i < position.length; i++ ) {
position[i].translate( dxy );
}
} else {
Position[] positions = sb.getExteriorRing().getPositions();
moveVertex( positions, dxy );
Ring[] inner = sb.getInteriorRings();
for ( Ring ring : inner ) {
positions = ring.getPositions();
moveVertex( positions, dxy );
}
}
}
/**
*
* @param positions
* @param dxy
*/
private void moveVertex( Position[] positions, double[] dxy ) {
double tolerance = sourcePoint.getTolerance();
for ( Position position : positions ) {
if ( GeometryUtils.distance( position, sourcePoint.getPosition() ) <= tolerance ) {
position.translate( dxy );
}
}
}
/*
* (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 featureCollection;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#isUndoSupported()
*/
public boolean isUndoSupported() {
return true;
}
/**
*
* @param feature
* @param geom
*/
protected void setGeometryProperty( Feature feature, Geometry geom ) {
FeatureProperty fp = feature.getProperties( geomProperty )[0];
fp.setValue( geom );
feature.setProperty( fp, 0 );
}
/**
*
* @param ring
* @return
*/
protected Position[] validateRing( Position[] ring ) {
if ( !ring[0].equals( ring[ring.length - 1] ) ) {
Position[] tmp = new Position[ring.length];
for ( int i = 0; i < ring.length; i++ ) {
tmp[i] = ring[i];
}
// ensure that first an last point are
tmp[tmp.length - 1] = GeometryFactory.createPosition( ring[0].getAsArray() );
ring = tmp;
}
return ring;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#undo()
*/
public void undo()
throws Exception {
if ( performed ) {
Iterator<Feature> iter = old.keySet().iterator();
while ( iter.hasNext() ) {
Feature feature = iter.next();
setGeometryProperty( feature, old.get( feature ) );
}
performed = false;
}
}
}