/* Spatial Operations & Editing Tools for uDig
*
* Axios Engineering under a funding contract with:
* Diputación Foral de Gipuzkoa, Ordenación Territorial
*
* http://b5m.gipuzkoa.net
* http://www.axios.es
*
* (C) 2006, Diputación Foral de Gipuzkoa, Ordenación Territorial (DFG-OT).
* DFG-OT agrees to licence under Lesser General Public License (LGPL).
*
* 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.text.MessageFormat;
import net.refractions.udig.project.ILayer;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import es.axios.udig.spatialoperations.internal.i18n.Messages;
import es.axios.udig.spatialoperations.internal.parameters.IClipParameters;
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;
/**
* Command executing clip operation
* <p>
* Validates data input and executes the clip operation
* The Client module must set the input data and evaluate
* precondition before execute the command
* </p>
* @author Mauricio Pazos (www.axios.es)
* @author Gabriel Roldan (www.axios.es)
* @since 1.1.0
*/
public final class ClipCommand extends SOAbstractCommand {
private static final Message INITIAL_MESSAGE = new Message(Messages.ClipCommand_clip_description,
Message.Type.IMPORTANT_INFO);
// Collaborators
private GeometryCompatibilityValidator geomValidator = new GeometryCompatibilityValidator();
// inputs values
private ILayer clippingLayer = null;
private ILayer layerToClip = null;
private FeatureCollection<SimpleFeatureType, SimpleFeature> featuresToClip = null;
private FeatureCollection<SimpleFeatureType, SimpleFeature> clippingFeatures = null;
private ILayer targetLayer = null;
private String targetLayerName = null;
private CoordinateReferenceSystem targetCrs = null;
private SimpleFeatureType targetFeatureType;
/**
* New instnce of ClipCommand
*
*/
public ClipCommand(){
super(INITIAL_MESSAGE);
reset();
}
/**
* Evaluates inputs data, if they have errors message error will be setted.
*
* @return true if inputs data are ok
*/
@Override
public boolean evalPrecondition(){
this.message = Message.NULL;
this.canExecute = true;
// clipping and cliped layer must be differents
if(this.layerToClip == null){
this.message = new Message(Messages.ClipCommand_must_select_clipped_layer,
Message.Type.INFORMATION);
this.canExecute = false;
}else if(this.clippingLayer== null){
this.message = new Message(Messages.ClipCommand_must_select_clipping_layer,
Message.Type.INFORMATION);
this.canExecute = false;
}else if(this.layerToClip.equals(this.clippingLayer)){
this.message = new Message(Messages.ClipCommand_clipping_and_clipped_must_be_differents,
Message.Type.ERROR);
this.canExecute = false;
} else if( (this.clippingFeatures.size() == 0) ){
this.message = new Message(Messages.ClipCommand_there_are_not_features_in_clipping_layer,
Message.Type.ERROR);
this.canExecute = false;
} else if( (this.featuresToClip.size() == 0) ){
this.message = new Message(Messages.ClipCommand_there_are_not_features_to_clip,
Message.Type.ERROR);
this.canExecute = false;
} else if(!validTarget()){
this.canExecute = false;
}else if((this.layerToClip!= null) && (this.targetLayer!=null) ){
if(this.layerToClip.equals(this.targetLayer)){
final String msg = MessageFormat.format(Messages.ClipCommand_will_clip_existent_layer, this.layerToClip.getName());
this.message = new Message(msg, Message.Type.WARNING);
this.canExecute = true; // this warning allow to execute the operation
}
}
if(this.canExecute){
// if there is a message setted it will be maintained else
// set de ok message as default.
if( this.message == Message.NULL ){
this.message = new Message(Messages.ClipCommand_parameters_ok,Message.Type.INFORMATION);
}
}
return this.canExecute;
}
/**
* Valid the target layer parameter
* @return
*/
private boolean validTarget() {
this.message = Message.NULL;
if ((this.targetLayerName == null) && (this.targetLayer == null)) {
this.message = new Message(Messages.ClipCommand_must_select_result,
Message.Type.INFORMATION);
return false;
} else if( (this.targetLayer != null) && (this.clippingLayer!= null) ){
if( this.targetLayer.equals(this.clippingLayer) ){
this.message = new Message(Messages.ClipCommand_clipping_and_result_must_be_differents,
Message.Type.ERROR);
return false;
}
} else if((this.targetLayerName != null) && this.targetLayerName.length() > 0){
//FIXME HACK then map's crs should be a command's parameter
this.targetCrs = this.layerToClip.getMap().getViewportModel().getCRS();
assert this.targetCrs != null;
//end hack
SimpleFeatureTypeBuilder typeBuilder = GeoToolsUtils.createDefaultFeatureType(this.targetLayerName, this.targetCrs);
try {
this.targetFeatureType = typeBuilder.buildFeatureType();
} catch (IllegalArgumentException e) {
this.message = new Message(Messages.BufferCommand_can_not_create_targetFeatureType,
Message.Type.ERROR);
return false;
}
}
// The geometry dimension of target layer must be
// equal to the layer to clip or MulyGeimetry compatible or Geometry
SimpleFeatureType featureType = this.layerToClip.getSchema();
GeometryDescriptor geomType = featureType.getDefaultGeometry();
Class expectedGeometry = geomType.getType().getBinding();
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.ClipCommand_failed_validating_geometry, Message.Type.FAIL);
return false;
}
return true;
}
/**
* Sets parameters
*
* @param clippingLayer
* @param layerToClip
* @param clippingFeatures
* @param featuresToClip
* @param targetLayer
*/
public void setParameters(
final ILayer clippingLayer, final ILayer layerToClip,
final FeatureCollection<SimpleFeatureType, SimpleFeature> clippingFeatures, final FeatureCollection<SimpleFeatureType, SimpleFeature> featuresToClip,
final ILayer targetLayer ) {
this.clippingLayer = clippingLayer;
this.layerToClip = layerToClip;
this.clippingFeatures = clippingFeatures;
this.featuresToClip = featuresToClip;
setTarget(targetLayer);
}
/**
* sets parameters
*
* @param clippingLayer
* @param layerToClip
* @param clippingFeatures
* @param featuresToClip
* @param targetLayerName
* @param targetCrs
*/
public void setParameters( final ILayer clippingLayer, final ILayer layerToClip,
final FeatureCollection<SimpleFeatureType, SimpleFeature> clippingFeatures,
final FeatureCollection<SimpleFeatureType, SimpleFeature> featuresToClip,
final String targetLayerName,
final CoordinateReferenceSystem targetCrs) {
this.clippingLayer = clippingLayer;
this.layerToClip = layerToClip;
this.clippingFeatures = clippingFeatures;
this.featuresToClip = featuresToClip;
setTarget(targetLayerName, targetCrs);
}
/**
* sets the target layer parameter
*
* @param targetLayer
*/
private void setTarget( final ILayer targetLayer ) {
this.targetLayer = targetLayer;
this.targetLayerName = null;
this.targetCrs = null;
}
/**
* sets the feature type for the new layer
*
* @param targetLayerName
* @param targetCrs
*/
private void setTarget( final String targetLayerName, final CoordinateReferenceSystem targetCrs ) {
this.targetLayer = null;
this.targetLayerName = targetLayerName;
this.targetCrs = targetCrs;
}
/**
* Executes the clip transaction
*
* @throws SOCommandException
*/
@Override
public void execute() throws SOCommandException{
if(! this.canExecute ) {
throw new SOCommandException("The precondition is false."); //$NON-NLS-1$
}
IClipParameters params;
if(this.targetLayer != null){
params = ParametersFactory.createClipParameters(this.clippingLayer, this.layerToClip,
this.clippingFeatures,
this.featuresToClip, this.targetLayer);
}else{
assert this.targetFeatureType != null;
params = ParametersFactory.createClipParameters(this.clippingLayer, this.layerToClip,
this.clippingFeatures,
this.featuresToClip, this.targetFeatureType);
}
try {
SOProcessManager.clipOperation(params);
} catch (SOProcessException e) {
throw new SOCommandException( e.getMessage());
}
reset();
}
@Override
public void initParameters() {
this.layerToClip = null;
this.clippingLayer = null;
this.featuresToClip = null;
this.clippingFeatures = null;
}
}