//$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.List; import java.util.UUID; import org.deegree.datatypes.QualifiedName; import org.deegree.framework.util.GeometryUtils; import org.deegree.igeo.dataadapter.DataAccessAdapter; import org.deegree.igeo.dataadapter.FeatureAdapter; import org.deegree.igeo.i18n.Messages; import org.deegree.kernel.Command; import org.deegree.kernel.CommandException; import org.deegree.model.feature.Feature; import org.deegree.model.feature.FeatureFactory; import org.deegree.model.feature.FeatureProperty; import org.deegree.model.feature.GeneratedValueFeatureProperty; import org.deegree.model.feature.ValueGenerator; import org.deegree.model.spatialschema.Aggregate; 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.MultiCurve; 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.SurfaceInterpolationImpl; /** * {@link Command} implementation for splitting a feature/geometry into two or more feature/geometries along a defined * {@link Curve}. * * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> * @author last edited by: $Author$ * * @version. $Revision$, $Date$ */ public class SplitFeatureCommand extends UngroupFeatureCommand { private static final QualifiedName name = new QualifiedName( "Split Feature Command" ); private Surface splitter; private Curve originalSplitter; /** * * @param dataAccessAdapter * @param feature * @param geomProperty * @param splitter * line that will split the geometries of the passed feature */ public SplitFeatureCommand( DataAccessAdapter dataAccessAdapter, Feature feature, QualifiedName geomProperty, Curve splitter ) { super( dataAccessAdapter, feature, geomProperty ); this.originalSplitter = splitter; this.splitter = (Surface) splitter.getBuffer( 0.000001, 1, Geometry.BUFFER_CAP_SQUARE ); } @Override protected void createNewFeatures( FeatureProperty[] geomFP ) throws GeometryException { resultFC = FeatureFactory.createFeatureCollection( UUID.randomUUID().toString(), 30 ); for ( FeatureProperty geometryProperty : geomFP ) { Geometry geometry = (Geometry) geometryProperty.getValue(); boolean a = geometry.contains( originalSplitter.getEndPoint() ) && !equalToVertex( geometry, originalSplitter.getEndPoint() ); boolean b = geometry.contains( originalSplitter.getStartPoint() ) && !equalToVertex( geometry, originalSplitter.getStartPoint() ); if ( a || b ) { throw new CommandException( Messages.get( "$DG10095" ) ); } List<Geometry> geometries = new ArrayList<Geometry>( 30 ); // this realizes splitting the original geometry. It works because the // splitter geometry is a very narrow polygon the divides a original // geometry into one or more parts Geometry geom = geometry.difference( splitter ); if ( geom instanceof Aggregate ) { Geometry[] geoms = ( (Aggregate) geom ).getAll(); for ( Geometry geometry2 : geoms ) { geometries.add( geometry2 ); } } else { geometries.add( geometry ); } // after splitting a geometry by a narrow polygon points must be moved to their neighbors if // distance is less than ~ double of splitting polygon thickness to ensure that result geometries // are really touching their direct neighbor List<Geometry> finalGeom = new ArrayList<Geometry>( geometries.size() ); for ( int i = 0; i < geometries.size(); i++ ) { Geometry geom1 = geometries.get( i ); if ( geom1 instanceof Surface ) { handleSurface( geometries, finalGeom, i, geom1 ); } else if ( geom1 instanceof Curve ) { Position[] g1Pos = ( (Curve) geom1 ).getAsLineString().getPositions(); g1Pos = clean( g1Pos, false ); for ( int j = i + 1; j < geometries.size(); j++ ) { Geometry geom2 = geometries.get( j ); Position[] g2Pos = ( (Curve) geom2 ).getAsLineString().getPositions(); g2Pos = clean( g2Pos, false ); for ( int k = 0; k < g1Pos.length; k++ ) { double minD = 9E9; int u = -1; for ( int k2 = 0; k2 < g2Pos.length; k2++ ) { double d = GeometryUtils.distance( g1Pos[k], g2Pos[k2] ); if ( d < 0.00001 && d < minD ) { u = k2; minD = d; } } if ( u > -1 ) { g1Pos[k] = GeometryFactory.createPosition( g2Pos[u].getX(), g2Pos[u].getY() ); } } } finalGeom.add( GeometryFactory.createCurve( g1Pos, geom1.getCoordinateSystem() ) ); } } FeatureProperty[] fp = feature.getProperties(); Feature defaultFeature = ( (FeatureAdapter) dataAccessAdapter ).getDefaultFeature( feature.getName() ); for ( Geometry geometry2 : finalGeom ) { FeatureProperty[] newFp = new FeatureProperty[fp.length]; for ( int i = 0; i < newFp.length; i++ ) { if ( fp[i].getName().equals( geometryProperty.getName() ) ) { newFp[i] = FeatureFactory.createFeatureProperty( geometryProperty.getName(), geometry2 ); } else { FeatureProperty tmpProperty = defaultFeature.getDefaultProperty( fp[i].getName() ); if ( tmpProperty instanceof GeneratedValueFeatureProperty ) { ValueGenerator valueGenerator = ( (GeneratedValueFeatureProperty) tmpProperty ).getValueGenerator(); newFp[i] = FeatureFactory.createGeneratedValueFeatureProperty( fp[i].getName(), valueGenerator ); } else { newFp[i] = FeatureFactory.createFeatureProperty( fp[i].getName(), fp[i].getValue() ); } } } Feature newFeature = FeatureFactory.createFeature( "ID_" + UUID.randomUUID().toString(), feature.getFeatureType(), newFp ); resultFC.add( newFeature ); } } } private void handleSurface( List<Geometry> geometries, List<Geometry> finalGeom, int i, Geometry geom1 ) throws GeometryException { Position[] g1Ext = ( (Surface) geom1 ).getSurfaceBoundary().getExteriorRing().getPositions(); g1Ext = clean( g1Ext, true ); for ( int j = i + 1; j < geometries.size(); j++ ) { Geometry geom2 = geometries.get( j ); if ( geom2 instanceof Surface ) { Position[] g2Ext = ( (Surface) geom2 ).getSurfaceBoundary().getExteriorRing().getPositions(); g2Ext = clean( g2Ext, true ); for ( int k = 0; k < g1Ext.length; k++ ) { double minD = 9E9; int u = -1; for ( int k2 = 0; k2 < g2Ext.length; k2++ ) { double d = GeometryUtils.distance( g1Ext[k], g2Ext[k2] ); if ( d < 0.00001 && d < minD ) { u = k2; minD = d; } } if ( u > -1 ) { g1Ext[k] = GeometryFactory.createPosition( g2Ext[u].getX(), g2Ext[u].getY() ); } } } } Position[][] g1IrPos = getInnerRings( geom1 ); Surface surface = GeometryFactory.createSurface( g1Ext, g1IrPos, new SurfaceInterpolationImpl(), geom1.getCoordinateSystem() ); surface = (Surface) GeometryUtils.ensureClockwise( surface ); finalGeom.add( surface ); } /** * * @param ext * @param close * @return */ private Position[] clean( Position[] ext, boolean close ) { List<Position> tmp = new ArrayList<Position>( ext.length ); tmp.add( ext[0] ); int k = 0; for ( int i = 0; i < ext.length; i++ ) { if ( GeometryUtils.distance( tmp.get( k ), ext[i] ) > 0.00001 ) { tmp.add( ext[i] ); k++; } } // ensure that first an last position are equal if ( close && !tmp.get( 0 ).equals( tmp.get( tmp.size() - 1 ) ) ) { tmp.add( tmp.get( tmp.size() - 1 ) ); } return tmp.toArray( new Position[tmp.size()] ); } /** * @param geometry * @param point * @return * @throws GeometryException */ private boolean equalToVertex( Geometry geometry, Point point ) throws GeometryException { geometry.setTolerance( 0.001 ); if ( geometry instanceof Curve ) { Curve curve = (Curve) geometry; Position[] positions = curve.getAsLineString().getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } } else if ( geometry instanceof Surface ) { Surface surface = (Surface) geometry; Position[] positions = surface.getSurfaceBoundary().getExteriorRing().getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } Ring[] rings = surface.getSurfaceBoundary().getInteriorRings(); for ( Ring ring : rings ) { positions = ring.getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } } } else if ( geometry instanceof MultiSurface ) { Curve[] curves = ( (MultiCurve) geometry ).getAllCurves(); for ( Curve curve : curves ) { Position[] positions = curve.getAsLineString().getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } } } else if ( geometry instanceof Surface ) { Surface[] surfaces = ( (MultiSurface) geometry ).getAllSurfaces(); for ( Surface surface : surfaces ) { Position[] positions = surface.getSurfaceBoundary().getExteriorRing().getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } Ring[] rings = surface.getSurfaceBoundary().getInteriorRings(); for ( Ring ring : rings ) { positions = ring.getPositions(); for ( Position position : positions ) { if ( position.equals( point.getPosition() ) ) { return true; } } } } } return false; } private Position[][] getInnerRings( Geometry geom1 ) { Position[][] irPos = null; Ring[] g1Ir = ( (Surface) geom1 ).getSurfaceBoundary().getInteriorRings(); if ( g1Ir != null && g1Ir.length > 0 ) { irPos = new Position[g1Ir.length][]; for ( int k = 0; k < g1Ir.length; k++ ) { irPos[k] = g1Ir[k].getPositions(); } } return irPos; } /* * (non-Javadoc) * * @see org.deegree.kernel.Command#getName() */ public QualifiedName getName() { return name; } }