/* uDig-Spatial Operations plugins * http://b5m.gipuzkoa.net * (C) 2006, DiputaciĆ³n Foral de Gipuzkoa, OrdenaciĆ³n Territorial. * * 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; * version 2.1 of the License. * * 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. */ package es.axios.udig.spatialoperations.internal.modelconnection; import java.util.ArrayList; import java.util.List; import net.refractions.udig.project.ILayer; import org.geotools.feature.FeatureCollection; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.GeometryDescriptor; import com.vividsolutions.jts.geom.Geometry; import es.axios.udig.spatialoperations.internal.i18n.Messages; import es.axios.udig.spatialoperations.internal.parameters.IIntersectParameters; import es.axios.udig.spatialoperations.internal.parameters.ParametersFactory; import es.axios.udig.spatialoperations.internal.processmanager.SOProcessException; import es.axios.udig.spatialoperations.internal.processmanager.SOProcessManager; import es.axios.udig.spatialoperations.ui.view.Message; import es.axios.udig.ui.commons.util.GeoToolsUtils; /** * Intersect Command * <p> * Evaluates predicate and executes the associated intersection operation. * </p> * * @author Mauricio Pazos (www.axios.es) * @author Gabriel Roldan (www.axios.es) * @since 1.1.0 */ public final class IntersectCommand extends SOAbstractCommand { private static final Message INITIAL_MESSAGE = new Message(Messages.IntersectCommand_description, Message.Type.IMPORTANT_INFO); // collaborators private GeometryCompatibilityValidator geomValidator = new GeometryCompatibilityValidator(); // inputs parameters private ILayer firstLayer = null; private FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInFirstLayer = null; private ILayer secondLayer = null; private FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInSecondLayer = null; private ILayer targetLayer = null; private SimpleFeatureType targetFeatureType = null; public IntersectCommand(){ super(INITIAL_MESSAGE); } /** * Sets the parameters to execute the operation * * @param firstLayer * @param featuresInFirstLayer * @param secondLayer * @param featuresInSecondLayer * @param targetLayer */ public void setParameters( ILayer firstLayer, FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInFirstLayer, ILayer secondLayer, FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInSecondLayer, ILayer targetLayer ) { this.firstLayer = firstLayer; this.featuresInFirstLayer = featuresInFirstLayer; this.secondLayer = secondLayer; this.featuresInSecondLayer = featuresInSecondLayer; setTarget( targetLayer ); } /** * sets the target layer parameter * * @param targetLayer */ private void setTarget( final ILayer targetLayer ) { this.targetLayer = targetLayer; this.targetFeatureType = null; } /** * Sets the parameters to execute the operation * * @param firstLayer * @param featuresInFirstLayer * @param secondLayer * @param featuresInSecondLayer * @param targetFeaureType * @param targetCrs */ public void setParameters( ILayer firstLayer, FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInFirstLayer, ILayer secondLayer, FeatureCollection<SimpleFeatureType, SimpleFeature> featuresInSecondLayer, SimpleFeatureType targetFeatureType) { this.firstLayer = firstLayer; this.featuresInFirstLayer = featuresInFirstLayer; this.secondLayer = secondLayer; this.featuresInSecondLayer = featuresInSecondLayer; setTarget( targetFeatureType); } /** * sets the feature type for the new layer * * @param featureType * @param targetCrs */ private void setTarget( final SimpleFeatureType featureType ) { this.targetLayer = null; this.targetFeatureType = featureType; } /** * Evaluates de compatibility of layer's geometries and not null inputs. * Additionaly first,second and target layer must be differens. * * @return true if all parameters are ok */ @Override public boolean evalPrecondition() { this.canExecute = true; if(hasNullParameters()){ this.canExecute = false; }else if( !checkInterLayerPredicate() ){ this.canExecute = false; } else if(!checkNoEmptyLayers() ){ this.canExecute = false; } else if(!checkTargetCompatibility() ){ this.canExecute = false; } // if can, set the ok message if(this.canExecute){ this.message = new Message(Messages.IntersectCommand_parameters_ok, Message.Type.INFORMATION); } return this.canExecute; } /** * @return true if the geometry of target is compatible with * the intersection geometry type */ private boolean checkTargetCompatibility() { this.message = Message.NULL; //The geometry dimension of target layer must be // equal to the minor of the source layers' dimension. Class expectedGeometry = getGeometryExpected(firstLayer, secondLayer); SimpleFeatureType targetType = (this.targetLayer != null) ? this.targetLayer.getSchema() : this.targetFeatureType; GeometryDescriptor geomAttr= targetType.getDefaultGeometry(); Class targetGeometry = geomAttr.getType().getBinding(); this.geomValidator.setExpected(expectedGeometry); this.geomValidator.setTarget(targetGeometry); try { if(!this.geomValidator.validate() ){ this.message = this.geomValidator.getMessage(); return false; } } catch (Exception e) { this.message = new Message( Messages.IntersectCommand_faild_validating_geometry_compatibility, Message.Type.FAIL); return false; } return true; } /** * first and second layer must have one or more features * * @return true if first and second layer have features. */ private boolean checkNoEmptyLayers() { this.message = Message.NULL; //first and second layer must have one or more features if( (this.featuresInFirstLayer.size() == 0) ){ this.message = new Message(Messages.IntersectCommand_there_is_not_features_to_intersect_in_first_layer, Message.Type.ERROR); return false; } if( (this.featuresInSecondLayer.size() == 0) ){ this.message = new Message(Messages.IntersectCommand_there_is_not_to_intersect_in_second_layer, Message.Type.ERROR); return false; } return true; } /** * The layers can not be equals * * @return true if the layers are differents */ private boolean checkInterLayerPredicate() { this.message = Message.NULL; List<ILayer> layerList = new ArrayList<ILayer>(3); layerList.add(this.firstLayer); if( layerList.contains(this.secondLayer) ){ this.message = new Message(Messages.IntersectCommand_first_and_second_must_be_differents, Message.Type.ERROR); return false; } layerList.add(this.secondLayer); if( layerList.contains(this.targetLayer) ){ layerList.add(this.firstLayer); this.message = new Message(Messages.IntersectCommand_first_sectond_and_target_must_be_differents, Message.Type.ERROR); return false; } return true; } /** * Checks if there are some null parameter and sets a human message. * * @return false if found any null parameter, true in other case. */ private boolean hasNullParameters() { this.message = Message.NULL; if(this.firstLayer == null){ this.message = new Message(Messages.IntersectCommand_must_select_the_first_layer, Message.Type.INFORMATION); return true; } if(this.secondLayer== null){ this.message = new Message(Messages.IntersectCommand_must_select_second_layer, Message.Type.INFORMATION); return true; } if ((this.targetLayer == null) && (this.targetFeatureType == null)) { this.message = new Message(Messages.IntersectCommand_must_select_target_layer, Message.Type.INFORMATION); return true; } return false; } /** * Analyses the source layers and produces the target geometry required * for target layer. * <p> * The result will be the layer's geometry that has the minimum dimension. * If someone of they has Geometry type the result must be Geometry * </p> * @param firstLayer * @param secondLayer * @return the geometry expected */ private Class getGeometryExpected( final ILayer firstLayer, final ILayer secondLayer){ SimpleFeatureType firstType = firstLayer.getSchema(); SimpleFeatureType secondType = secondLayer.getSchema(); // first checks if some of layers have got Geometry class // If that is true returns Geometry class. GeometryDescriptor firstGeomAttr = firstType.getDefaultGeometry(); Class firstGeomClass = firstGeomAttr.getType().getBinding(); GeometryDescriptor secondGeomAttr = secondType.getDefaultGeometry(); Class secondGeomClass = secondGeomAttr.getType().getBinding(); if(Geometry.class.equals(firstGeomClass) || Geometry.class.equals(secondGeomClass)){ return Geometry.class; } // if they have not got Geometry class checks the dimension and // return the class of minimum int firstLayerDim = GeoToolsUtils.getDimensionOf(firstType); int secondLayerDim = GeoToolsUtils.getDimensionOf(secondType); SimpleFeatureType featureTypeExpected; if(firstLayerDim <= secondLayerDim){ featureTypeExpected = firstType; }else{ featureTypeExpected = secondType; } GeometryDescriptor geomType = featureTypeExpected.getDefaultGeometry(); Class geomClass = geomType.getType().getBinding(); return geomClass; } /** * Executes the intersect operation. */ @Override public void execute() throws SOCommandException { if(! this.canExecute ) { throw new SOCommandException("the precondition is false."); //$NON-NLS-1$ } // Creates the required parameters to create new layer or use an existent layer. IIntersectParameters params = null; if (this.targetLayer != null) { params = ParametersFactory.createIntersectParameters(this.firstLayer, this.featuresInFirstLayer, this.secondLayer, this.featuresInSecondLayer, this.targetLayer); } else{ params = ParametersFactory.createIntersectParameters(this.firstLayer, this.featuresInFirstLayer, this.secondLayer, this.featuresInSecondLayer, this.targetFeatureType); } try { SOProcessManager.intersectOperation(params); } catch (SOProcessException e) { throw new SOCommandException(e.getMessage()); } reset(); } @Override public void initParameters() { firstLayer = null; featuresInFirstLayer = null; secondLayer = null; featuresInSecondLayer = null; targetLayer = null; targetFeatureType = null; } }