/* 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.tasks; import java.util.List; import java.util.logging.Logger; import org.geotools.data.FeatureStore; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.opengis.feature.IllegalAttributeException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.OperationNotFoundException; import org.opengis.referencing.operation.TransformException; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateArrays; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.CoordinateSequenceFactory; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.util.LineStringExtracter; import es.axios.geotools.util.FeatureUtil; import es.axios.geotools.util.GeoToolsUtils; /** * Convert the features from polygon to lineString. * * @author Aritz Davila (www.axios.es) * @author Mauricio Pazos (www.axios.es) * @since 1.2.0 */ final class PolygonToLineTask extends AbstractSpatialOperationTask<SimpleFeatureStore> implements IPolygonToLineTask { private static final Logger LOGGER = Logger .getLogger(PolygonToLineTask.class .getName()); private CoordinateReferenceSystem sourceLayerCrs = null; private FeatureCollection<SimpleFeatureType, SimpleFeature> featuresFromSource = null; private Boolean explode = null; // private String newAttributeName = null; /** * To create an instance must use * {@link #createProcess(FeatureStore, FeatureCollection, CoordinateReferenceSystem, String)} */ private PolygonToLineTask() { } /** * Create the polygon to line process implementation. * * @param targetStore * @param featuresFromSource * @param sourceLayerCrs * @param explode * @return */ public static IPolygonToLineTask createProcess( final SimpleFeatureStore targetStore, final FeatureCollection<SimpleFeatureType, SimpleFeature> featuresFromSource, final CoordinateReferenceSystem sourceLayerCrs, final Boolean explode) { assert targetStore != null; assert featuresFromSource != null; assert sourceLayerCrs != null; assert explode != null; // assert newAttributeName != null; PolygonToLineTask task = new PolygonToLineTask(); task.targetStore = targetStore; task.featuresFromSource = featuresFromSource; task.sourceLayerCrs = sourceLayerCrs; task.explode = explode; // task.newAttributeName = newAttributeName; return task; } @Override protected SimpleFeatureStore getResult() { return this.targetStore; } @Override protected void perform() throws SpatialOperationException { FeatureIterator<SimpleFeature> iter = null; SimpleFeature featureToTransform = null; try { iter = featuresFromSource.features(); SimpleFeatureType featureType = this.targetStore.getSchema(); final CoordinateReferenceSystem targetLayerCrs = featureType.getGeometryDescriptor() .getCoordinateReferenceSystem(); while (iter.hasNext()) { featureToTransform = iter.next(); Geometry defaultGeometry = (Geometry) featureToTransform.getDefaultGeometry(); if (defaultGeometry.isValid()) { if (explode) { createFeatureExplode(featureToTransform, targetLayerCrs, featureType); } else { createFeature(featureToTransform, targetLayerCrs, featureType); } } else { LOGGER.severe("Not a valid geometry!! \nFID: " + featureToTransform.getID() + "\nGeometry: " //$NON-NLS-1$ + defaultGeometry.toText()); } } } catch (Exception e) { throw makeException(e, e.getMessage()); } finally { if (iter != null) { iter.close(); } } } /** * Convert each segment of the polygon feature in one lineString feature and * inserts it. * * @param featureToTransform * Feature to explode * @param targetLayerCrs * Target layer CRS * @param featureType * Target featureType * @throws OperationNotFoundException * @throws TransformException * @throws IllegalAttributeException * @throws SpatialOperationException */ private void createFeatureExplode( SimpleFeature featureToTransform, CoordinateReferenceSystem targetLayerCrs, SimpleFeatureType featureType) throws OperationNotFoundException, TransformException, IllegalAttributeException, SpatialOperationException { SimpleFeature transformedFeature; Coordinate[] newCoor; Geometry lines = convertToLine(featureToTransform, targetLayerCrs); // get the geometries of that feature. List<? extends Geometry> linesList = LineStringExtracter.getLines(lines); for (Geometry lineSegment : linesList) { // get the coordinates list of each geometry. Coordinate[] coorList = lineSegment.getCoordinates(); Coordinate[] coordFiltered = CoordinateArrays.removeRepeatedPoints(coorList); GeometryFactory gfac = lineSegment.getFactory(); CoordinateSequenceFactory coorFac = gfac.getCoordinateSequenceFactory(); CoordinateSequence coordinates; for (int i = 0; i < coordFiltered.length - 1; i++) { // for each geometry, create lineStrings as sides has the // geometry. newCoor = new Coordinate[2]; newCoor[0] = coordFiltered[i]; newCoor[1] = coordFiltered[i + 1]; coordinates = coorFac.create(newCoor); LineString lineString = gfac.createLineString(coordinates); transformedFeature = FeatureUtil.createFeatureUsing(featureToTransform, featureType, lineString); insert(targetStore, transformedFeature); } } } /** * Convert the polygon feature into a lineString feature and inserts it. * * @param featureToTransform * The polygon feature. * @param targetLayerCrs * Target CRS. * @param featureType * Target feature type. * @throws OperationNotFoundException * @throws TransformException * @throws IllegalAttributeException * @throws SpatialOperationException */ private void createFeature( SimpleFeature featureToTransform, CoordinateReferenceSystem targetLayerCrs, SimpleFeatureType featureType) throws OperationNotFoundException, TransformException, IllegalAttributeException, SpatialOperationException { Geometry mlineString; mlineString = convertToLine(featureToTransform, targetLayerCrs); // the new feature will belong to this ID SimpleFeature transformedFeature = FeatureUtil.createFeatureUsing(featureToTransform, featureType, mlineString); insert(targetStore, transformedFeature); } /** * Convert the geometry of this feature( a polygon geometry ) to LineString * geometry. * * @param featureToTransform * The feature to be converted. * @param targetLayerCrs * Target layer CRS. * * @return The converted geometry which one will be a lineString geometry. * * @throws OperationNotFoundException * @throws TransformException */ private Geometry convertToLine(SimpleFeature featureToTransform, CoordinateReferenceSystem targetLayerCrs) throws OperationNotFoundException, TransformException { // project the base geometry to map Geometry baseGeometry = (Geometry) featureToTransform.getDefaultGeometry(); Geometry baseGeomOnMapCrs = GeoToolsUtils.reproject(baseGeometry, sourceLayerCrs, targetLayerCrs); Geometry boundary = baseGeomOnMapCrs.getBoundary(); return boundary; } }