/* 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.ui.taskmanager;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.measure.converter.UnitConverter;
import javax.measure.unit.Unit;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.IMap;
import net.refractions.udig.project.render.IViewportModel;
import org.eclipse.core.runtime.IProgressMonitor;
import org.geotools.data.FeatureStore;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.FeatureCollection;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Coordinate;
import es.axios.geotools.util.GeoToolsUtils;
import es.axios.geotools.util.UnitList;
import es.axios.udig.spatialoperations.internal.i18n.Messages;
import es.axios.udig.spatialoperations.internal.parameters.IBufferInExistentLayerParameters;
import es.axios.udig.spatialoperations.internal.parameters.IBufferInNewLayerParameters;
import es.axios.udig.spatialoperations.internal.parameters.IBufferParameters;
import es.axios.udig.spatialoperations.tasks.IBufferTask;
import es.axios.udig.spatialoperations.tasks.SpatialOperationFactory;
import es.axios.udig.ui.commons.mediator.AppGISMediator;
import es.axios.udig.ui.commons.util.LayerUtil;
import es.axios.udig.ui.commons.util.MapUtil;
/**
* Monitoring the buffer operation.
*
* @author Mauricio Pazos (www.axios.es)
* @author Aritz Davila (www.axios.es)
*
*/
final class BufferMonitor extends SOTaskMonitor<FeatureStore<SimpleFeatureType, SimpleFeature>> {
private Future<FeatureStore<SimpleFeatureType, SimpleFeature>> future;
private IBufferParameters params;
private ILayer sourceLayer = null;
private CoordinateReferenceSystem sourceCRS = null;
private ILayer targetLayer = null;
private CoordinateReferenceSystem targetCRS = null;
/**
* New instance of {@link BufferMonitor}. Clients must use
* {@link #newInstance(IBufferParameters)}.
*
* @param params
*/
private BufferMonitor(final IBufferParameters params) {
assert params != null;
this.params = params;
}
public static ISOTaskMonitor newInstance(IBufferParameters params) {
return new BufferMonitor(params);
}
/**
* sets the source feature collection to process and the target (or result)
* feature store
*/
@Override
protected void initTaskMonitor(IProgressMonitor progress) throws InvocationTargetException {
this.sourceLayer = params.getSourceLayer();
assert this.sourceLayer != null;
this.sourceCRS = params.getSourceCRS();
assert this.sourceCRS != null;
Filter filter = params.getFilter();
assert filter != null;
FeatureCollection<SimpleFeatureType, SimpleFeature> selectedFeatures;
try {
selectedFeatures = LayerUtil.getSelectedFeatures(this.sourceLayer, filter);
assert selectedFeatures != null;
SimpleFeatureStore targetStore = getTargetStore(selectedFeatures, this.params,
progress);
final CoordinateReferenceSystem mapCrs = MapUtil.getCRS(getMap());
final Unit<?> mapUnits = GeoToolsUtils.getDefaultCRSUnit(mapCrs);
final Unit<?> targetUnits = params.getUnitsOfMeasure();
double widthConverted = convertBufferWidth(params.getWidth(), mapUnits, targetUnits);
IBufferTask task = SpatialOperationFactory.createBuffer(selectedFeatures, targetStore, mapCrs,
widthConverted, params.getUnitsOfMeasure(), params.isMergeGeometries(), params
.getQuadrantSegments(), params.getCapStyle(), sourceCRS, targetCRS);
ExecutorService executor = Executors.newCachedThreadPool();
this.future = executor.submit(task);
progress.worked(1);
} catch (IOException e) {
throw makeInitializeExcepion(progress, e);
}
}
/**
* Converts the distance <code>bufferWidth</code>
* from/home/mauro/workspaces-eclipse/udig-ext/udig-extensions-1.2.x-sdk-1.1
* .x <code>targetUnits</code> to <code>sourceUnits</code>
*
* @param bufferWidth
* @param sourceUnits
* @param targetUnits
* @return
*/
private double convertBufferWidth(double bufferWidth, final Unit<?> sourceUnits, final Unit<?> targetUnits) {
assert sourceUnits != null;
assert targetUnits != null;
double convertedWidth;
if (UnitList.PIXEL_UNITS.equals(targetUnits)) {
IViewportModel viewportModel = this.sourceLayer.getMap().getViewportModel();
Coordinate origin = viewportModel.pixelToWorld(0, 0);
int fixedBufferWidth = (int) Math.round(bufferWidth);
Coordinate originPlusWidth = viewportModel.pixelToWorld(fixedBufferWidth, fixedBufferWidth);
convertedWidth = Math.abs(originPlusWidth.x - origin.x);
} else {
UnitConverter converter = targetUnits.getConverterTo(sourceUnits);
convertedWidth = converter.convert(bufferWidth);
}
return convertedWidth;
}
/**
* Returns the associated {@link FeatureStore} to the targetLayer or a new
* {@link FeatureStore} associated to a new target layer will be created in
* the map
*/
private SimpleFeatureStore getTargetStore( final FeatureCollection<SimpleFeatureType, SimpleFeature> selectedFeatures,
final IBufferParameters params,
final IProgressMonitor progress)
throws IOException {
SimpleFeatureStore targetStore;
if (params instanceof IBufferInExistentLayerParameters) {
targetLayer = ((IBufferInExistentLayerParameters) params).getTargetLayer();
assert this.targetLayer != null;
targetCRS = ((IBufferInExistentLayerParameters) params).getTargetCRS();
assert this.targetCRS != null;
targetStore = getFeatureStore(targetLayer);
} else { // a new layer is required IBufferInNewLayerParameters !=
// null
// create new layer (store and resource) with the feature type
// required
SimpleFeatureType featureType = ((IBufferInNewLayerParameters) params).getTargetFeatureType();
IGeoResource targetGeoResource = AppGISMediator.createTempGeoResource(featureType);
assert targetGeoResource != null;
targetStore = (SimpleFeatureStore) targetGeoResource.resolve(FeatureStore.class, progress);
this.targetLayer = addLayerToMap(getMap(), targetGeoResource);
assert this.targetLayer != null;
this.targetCRS = targetLayer.getCRS();
assert this.targetCRS != null;
// targetStore.getSchema().getDefaultGeometry().getCoordinateSystem();
}
assert targetStore != null;
return targetStore;
}
@Override
protected void deliveryResult(Future<FeatureStore<SimpleFeatureType, SimpleFeature>> future, ILayer target) {
presentFeaturesOnTargetLayer(target);
}
@Override
protected String getBeginMessage() {
return Messages.BufferProcess_subtaskBufferringFeatures;
}
@Override
protected String getCancelMessage() {
return Messages.BufferProcess_canceled;
}
@Override
protected String getDoneMessage() {
return Messages.BufferMonitor_successful;
}
@Override
protected Future<FeatureStore<SimpleFeatureType, SimpleFeature>>getFuture() {
return this.future;
}
@Override
protected IMap getMap() {
IMap map = this.sourceLayer.getMap();
assert map != null;
return map;
}
@Override
protected ILayer getTarget() {
return this.targetLayer;
}
}