/*
* uDig Spatial Operations - Tutorial - http://www.axios.es (C) 2009,
* Axios Engineering S.L. This product 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 product is distributed as part of tutorial, 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.tutorial.ui.centroid;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.IMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.geotools.data.FeatureStore;
import org.geotools.data.Transaction;
import org.geotools.data.simple.SimpleFeatureStore;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import es.axios.geotools.util.FeatureUtil;
import es.axios.udig.spatialoperations.tutorial.process.centroid.CentroidTask;
import es.axios.udig.spatialoperations.ui.common.ProjectionValidator;
import es.axios.udig.spatialoperations.ui.parameters.SOCommandException;
import es.axios.udig.spatialoperations.ui.parameters.SpatialOperationCommand;
import es.axios.udig.spatialoperations.ui.taskmanager.SOFeatureStore;
import es.axios.udig.ui.commons.mediator.AppGISMediator;
import es.axios.udig.ui.commons.message.InfoMessage;
import es.axios.udig.ui.commons.util.DialogUtil;
import es.axios.udig.ui.commons.util.MapUtil;
/**
*
* Checks the centroid parameters and executes the {@link CentroidTask} that
* creates the centroid features in the target layer.
*
* @author Mauricio Pazos (www.axios.es)
*
*/
public final class CentroidCommand extends SpatialOperationCommand {
private static final InfoMessage DEFAULT_MESSAGE = new InfoMessage("Calculate the polygon's centroid", //$NON-NLS-1$
InfoMessage.Type.IMPORTANT_INFO);
private ProjectionValidator projectionValidator = new ProjectionValidator();
// Parameters
private ILayer sourceLayer = null;
private IMap map = null;
private Filter sourceFilter = null;
public CentroidCommand() {
super(DEFAULT_MESSAGE);
}
public String getOperationID() {
return "Centroid"; //$NON-NLS-1$
}
public String getOperationName() {
return "Centroid"; //$NON-NLS-1$
}
public String getToolTipText() {
return "Makes the centroid of polygons' layer or selected polygons"; //$NON-NLS-1$
}
/**
* Checks all centroid parameters. It sets the error message if an invalid
* parameter is found.
*
* @return true if all parameter are OK, false in other case.
*/
@Override
protected boolean validateParameters() {
this.message = DEFAULT_MESSAGE;
if (!checkLayers())
return false;
if (!checkFilter(this.sourceFilter)) {
return false;
}
if (!checkSourceCRS())
return false;
if (getTargetLayer() != null) {
// if an existent layer is set its crs is checked.
if (!checkTargetCRS())
return false;
}
return true;
}
/**
* @return true if is possible project from source CRS to map CRS, false in
* other case.
*/
private boolean checkSourceCRS() {
assert sourceLayer != null;
assert map != null;
CoordinateReferenceSystem sourceCrs = sourceLayer.getCRS();
if (sourceCrs == null) {
this.message = new InfoMessage("The source layer doesn't have a CRS", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
CoordinateReferenceSystem mapCrs = MapUtil.getCRS(map);
if (mapCrs == null) {
this.message = new InfoMessage("The Map doesn't have a CRS", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
if (!canProjectFromCrsToCrs(sourceCrs, mapCrs))
return false;
return true;
}
/**
* @return true if is possible project from map CRS to target CRS, false in
* other case.
*/
private boolean checkTargetCRS() {
assert getTargetLayer() != null;
assert this.map != null;
CoordinateReferenceSystem targetCrs = getTargetLayer().getCRS();
if (targetCrs == null) {
this.message = new InfoMessage("The target layer doesn't have the CRS", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
CoordinateReferenceSystem mapCrs = MapUtil.getCRS(map);
if (mapCrs == null) {
this.message = new InfoMessage("The map doesn't have the CRS", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
if (!canProjectFromCrsToCrs(targetCrs, mapCrs))
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 checkLayers() {
if (this.sourceLayer == null) {
this.message = new InfoMessage("Must select the source layer", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
if ((getTargetLayer() == null) && (getTargetLayerName() == null) && (getTargetLayerGeometryClass() == null)) {
this.message = new InfoMessage("Must specify the target layer for the centroid result", //$NON-NLS-1$
InfoMessage.Type.ERROR);
return false;
}
if (this.sourceLayer.equals(getTargetLayer())) {
this.message = new InfoMessage("Source and Target layer should be differents", InfoMessage.Type.ERROR); //$NON-NLS-1$
return false;
}
return true;
}
private boolean canProjectFromCrsToCrs(CoordinateReferenceSystem fromCrs, CoordinateReferenceSystem toCrs) {
assert fromCrs != null;
assert toCrs != null;
this.message = InfoMessage.NULL;
try {
this.projectionValidator.setSourceCrs(fromCrs);
this.projectionValidator.setTargetCrs(toCrs);
if (!this.projectionValidator.validate()) {
this.message = this.projectionValidator.getMessage();
return false;
}
} catch (Exception e) {
final String msg = MessageFormat.format("CRS error: ", e.getMessage()); //$NON-NLS-1$
this.message = new InfoMessage(msg, InfoMessage.Type.FAIL);
return false;
}
return true;
}
@Override
public void executeOperation() throws SOCommandException {
final NullProgressMonitor progress = new NullProgressMonitor();
try {
final SimpleFeatureStore source = getFeatureStore(sourceLayer);
final SimpleFeatureStore target = getTargetStore();
final CoordinateReferenceSystem sourceCRS = getSourceCRS();
final CoordinateReferenceSystem mapCrs = getMapCRS();
final CoordinateReferenceSystem targetCRS =
(getTargetLayer() != null) ?
getTargetLayer().getCRS():
getMapCRS();
progress.setTaskName("Centroid Spatial Operation"); //$NON-NLS-1$
String msg = MessageFormat.format("Doing the ceentoid of {0}", sourceLayer.getName()); //$NON-NLS-1$
progress.beginTask(msg, IProgressMonitor.UNKNOWN);
IRunnableWithProgress runner = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
CentroidTask task = new CentroidTask(source, sourceCRS, sourceFilter, target, targetCRS, mapCrs);
task.run();
}
};
DialogUtil.runInProgressDialog("executing centroid task", true, runner, true, true); //$NON-NLS-1$
} catch (Exception e) {
throw new SOCommandException(e.getMessage());
} finally{
progress.done();
}
}
private CoordinateReferenceSystem getMapCRS() {
return MapUtil.getCRS(map);
}
private final CoordinateReferenceSystem getSourceCRS() {
if (this.sourceLayer != null) {
return this.sourceLayer.getCRS();
} else {
return null;
}
}
/**
*
* Analyzes what is the target specified, that is new layer o existent layer
* As lateral effect if the targetLayer is null this method create a new one
*
* @return the target FeatureStore
* @throws SOCommandException
*/
private final SimpleFeatureStore getTargetStore() throws SOCommandException {
SimpleFeatureStore targetStore = null;
if (getTargetLayer() != null) {
targetStore = this.getFeatureStore(getTargetLayer());
} else { // create a new layer
ILayer targetLayer = createNewLayer();
IGeoResource targetGeoResource = targetLayer.getGeoResource();
try {
targetStore = (SimpleFeatureStore) targetGeoResource.resolve(FeatureStore.class, null);
} catch (IOException e) {
throw new SOCommandException(e.getMessage());
}
}
Transaction transaction = ((net.refractions.udig.project.internal.Map) this.map).getEditManagerInternal()
.getTransaction();
SOFeatureStore soStore = new SOFeatureStore( targetStore, transaction);
return soStore;
}
/**
* Creates a new layer
*
* @return {@link ILayer}
* @throws SOCommandException
*/
private final ILayer createNewLayer() throws SOCommandException {
SimpleFeatureStore targetStore;
try {
SimpleFeatureType type = FeatureUtil.createFeatureType(this.sourceLayer.getSchema(), getTargetLayerName(),
getMapCRS(), getTargetLayerGeometryClass());
IGeoResource targetGeoResource = AppGISMediator.createTempGeoResource(type);
assert targetGeoResource != null;
targetStore = (SimpleFeatureStore) targetGeoResource.resolve(FeatureStore.class, null);
assert targetStore != null;
ILayer newLayer = MapUtil.addLayerToMap((IMap) this.map, targetGeoResource);
return newLayer;
} catch (Exception e) {
e.printStackTrace();
throw new SOCommandException(e);
}
}
/**
* @param layer
* @return the feature store associated to the layer
* @throws SOCommandException
*/
private final SimpleFeatureStore getFeatureStore(final ILayer layer)
throws SOCommandException {
assert layer != null;
IGeoResource resource = layer.getGeoResource();
if (resource == null) {
throw new SOCommandException("The layer does not have GeoResource"); //$NON-NLS-1$
}
try {
SimpleFeatureStore store = (SimpleFeatureStore) resource.resolve(FeatureStore.class, new NullProgressMonitor());
Transaction transaction = ((net.refractions.udig.project.internal.Map) this.map)
.getEditManagerInternal().getTransaction();
SOFeatureStore soStore = new SOFeatureStore(store, transaction);
return soStore;
} catch (IOException e) {
throw new SOCommandException(e.getMessage());
}
}
@Override
protected final Object[] getValidTargetLayerGeometries() {
Object[] geometryClasses = new Object[] { Point.class, MultiPoint.class, Geometry.class };
return geometryClasses;
}
@Override
protected final Object[] getSourceGeomertyClass() {
Object[] geometryClasses = new Object[] {
LineString.class,
MultiLineString.class,
Polygon.class,
MultiPolygon.class };
return geometryClasses;
}
@Override
public final void initParameters() {
setMap(null);
setSourceLayer(null);
setSourceFilter(null);
}
public final void setMap(final IMap map) {
this.map = map;
}
/**
*
* @param sourceLayer
* the source layer to set
*/
public final void setSourceLayer(final ILayer sourceLayer) {
this.sourceLayer = sourceLayer;
}
public final ILayer getSourceLayer() {
return this.sourceLayer;
}
public final void setSourceFilter(final Filter filter) {
this.sourceFilter = filter;
}
}