Statistics
| Revision:

root / org.gvsig.toolbox / trunk / org.gvsig.toolbox / org.gvsig.toolbox.algorithm / src / main / java / es / unex / sextante / vectorTools / fixedDistanceBuffer / FixedDistanceBufferAlgorithm.java @ 59

History | View | Annotate | Download (12.4 KB)

1

    
2

    
3
package es.unex.sextante.vectorTools.fixedDistanceBuffer;
4

    
5
import java.util.ArrayList;
6
import java.util.Stack;
7

    
8
import com.vividsolutions.jts.geom.Geometry;
9
import com.vividsolutions.jts.geom.GeometryCollection;
10
import com.vividsolutions.jts.geom.GeometryFactory;
11
import com.vividsolutions.jts.geom.MultiPolygon;
12
import com.vividsolutions.jts.geom.Polygon;
13
import com.vividsolutions.jts.operation.buffer.BufferOp;
14
import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
15

    
16
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
17
import es.unex.sextante.additionalInfo.AdditionalInfoVectorLayer;
18
import es.unex.sextante.core.GeoAlgorithm;
19
import es.unex.sextante.core.Sextante;
20
import es.unex.sextante.dataObjects.IFeature;
21
import es.unex.sextante.dataObjects.IFeatureIterator;
22
import es.unex.sextante.dataObjects.IVectorLayer;
23
import es.unex.sextante.dataObjects.vectorFilters.BoundingBoxFilter;
24
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
25
import es.unex.sextante.exceptions.RepeatedParameterNameException;
26
import es.unex.sextante.outputs.OutputVectorLayer;
27

    
28

    
29
public class FixedDistanceBufferAlgorithm
30
         extends
31
            GeoAlgorithm {
32

    
33
   public static final byte   BUFFER_INSIDE_POLY         = 1;
34
   public static final byte   BUFFER_OUTSIDE_POLY        = 0;
35
   public static final byte   BUFFER_INSIDE_OUTSIDE_POLY = 2;
36

    
37
   public static final String RESULT                     = "RESULT";
38
   public static final String NOTROUNDED                 = "NOTROUNDED";
39
   public static final String RINGS                      = "RINGS";
40
   public static final String TYPE                       = "TYPES";
41
   public static final String LAYER                      = "LAYER";
42
   public static final String DISTANCE                   = "DISTANCE";
43

    
44
   private IVectorLayer       m_Output;
45
   private boolean            m_bRounded;
46
   private int                m_iRings;
47
   private int                m_iType;
48
   private int                numProcessed               = 0;
49
   private double             m_dDistance;
50

    
51

    
52
   @Override
53
   public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
54

    
55
      final IVectorLayer layerIn = m_Parameters.getParameterValueAsVectorLayer(LAYER);
56
      if (!m_bIsAutoExtent) {
57
         layerIn.addFilter(new BoundingBoxFilter(m_AnalysisExtent));
58
      }
59

    
60
      m_dDistance = m_Parameters.getParameterValueAsDouble(DISTANCE);
61
      m_bRounded = !m_Parameters.getParameterValueAsBoolean(NOTROUNDED);
62
      m_iRings = m_Parameters.getParameterValueAsInt(RINGS);
63
      m_iType = m_Parameters.getParameterValueAsInt(TYPE);
64

    
65
      final int iFieldCount = layerIn.getFieldCount();
66
      Class types[];
67
      String[] sFieldNames;
68

    
69
      if (layerIn.getShapeType() != IVectorLayer.SHAPE_TYPE_POLYGON) {
70
         m_iType = BUFFER_OUTSIDE_POLY;
71
      }
72

    
73
      if (m_iType == BUFFER_INSIDE_OUTSIDE_POLY) {
74
         types = new Class[iFieldCount + 3];
75
         types[0] = Long.class;
76
         types[1] = Double.class;
77
         sFieldNames = new String[iFieldCount + 3];
78
         sFieldNames[0] = "ID";
79
         sFieldNames[1] = "FROM";
80
         sFieldNames[1] = "TO";
81
         for (int i = 0; i < iFieldCount; i++) {
82
            sFieldNames[i + 3] = layerIn.getFieldName(i);
83
            types[i + 3] = layerIn.getFieldType(i);
84
         }
85
      }
86
      else {
87
         types = new Class[iFieldCount + 2];
88
         types[0] = Long.class;
89
         types[1] = Double.class;
90
         sFieldNames = new String[iFieldCount + 2];
91
         sFieldNames[0] = "ID";
92
         sFieldNames[1] = "DIST";
93
         for (int i = 0; i < iFieldCount; i++) {
94
            sFieldNames[i + 2] = layerIn.getFieldName(i);
95
            types[i + 2] = layerIn.getFieldType(i);
96
         }
97
      }
98

    
99
      m_Output = getNewVectorLayer(RESULT, "Buffer", IVectorLayer.SHAPE_TYPE_POLYGON, types, sFieldNames);
100

    
101
      int i = 0;
102
      final int iTotal = layerIn.getShapesCount();
103
      final IFeatureIterator iter = layerIn.iterator();
104
      while (iter.hasNext() && setProgress(i, iTotal)) {
105
         final IFeature feature = iter.next();
106
         computeBuffer(feature.getGeometry(), m_dDistance, feature.getRecord().getValues());
107
         i++;
108
      }
109
      iter.close();
110

    
111
      return !m_Task.isCanceled();
112

    
113
   }
114

    
115

    
116
   @Override
117
   public void defineCharacteristics() {
118

    
119
      //      final String[] sRings = { Integer.toString(1), Integer.toString(2), Integer.toString(3) };
120

    
121
      final String[] sType = { Sextante.getText("Outer_buffer"), Sextante.getText("Inner_buffer"), Sextante.getText("Both"), };
122

    
123
      setName(Sextante.getText("Fixed_distance_buffer"));
124
      setGroup(Sextante.getText("Buffers"));
125
      setUserCanDefineAnalysisExtent(true);
126

    
127
      try {
128
         m_Parameters.addInputVectorLayer(LAYER, Sextante.getText("Input_layer"), AdditionalInfoVectorLayer.SHAPE_TYPE_ANY, true);
129
         m_Parameters.addNumericalValue(DISTANCE, Sextante.getText("Distance"),
130
                  AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE, 100, 0, Double.MAX_VALUE);
131
         m_Parameters.addSelection(TYPE, Sextante.getText("Buffer_type"), sType);
132
         //         m_Parameters.addSelection(RINGS, Sextante.getText("Number_of_concentric_rings"), sRings);
133
         m_Parameters.addNumericalValue(RINGS, Sextante.getText("Number_of_concentric_rings"),
134
                  AdditionalInfoNumericalValue.NUMERICAL_VALUE_INTEGER, 100, 1, Integer.MAX_VALUE);
135
         m_Parameters.addBoolean(NOTROUNDED, Sextante.getText("Do_not_round_resulting_polygons"), false);
136

    
137
         addOutputVectorLayer(RESULT, Sextante.getText("Buffer"), OutputVectorLayer.SHAPE_TYPE_POLYGON);
138
      }
139
      catch (final RepeatedParameterNameException e) {
140
         Sextante.addErrorToLog(e);
141
      }
142

    
143
   }
144

    
145

    
146
   //*********** code adapted from BufferVisitor class, by Alvaro Zabala*******************//
147

    
148
   public void computeBuffer(final Geometry originalGeometry,
149
                             final double bufferDistance,
150
                             final Object[] record) {
151
      Geometry solution = null;
152
      Geometry inputParam = originalGeometry;
153
      /*
154
       * When we try to apply large buffer distances, we could get OutOfMemoryError
155
       * exceptions. Explanation in
156
       * http://lists.jump-project.org/pipermail/jts-devel/2005-February/000991.html
157
       * http://lists.jump-project.org/pipermail/jts-devel/2005-September/001292.html
158
       * This problems hasnt been resolved in JTS 1.7.
159
       */
160
      if (originalGeometry.getDimension() != 0) {
161
         inputParam = TopologyPreservingSimplifier.simplify(originalGeometry, bufferDistance / 10d);
162
      }
163
      int cap = BufferOp.CAP_ROUND;
164
      if (!m_bRounded) {
165
         cap = BufferOp.CAP_SQUARE;
166
      }
167

    
168
      //this two references are necessary to compute radial rings
169
      Geometry previousExteriorRing = null;
170
      Geometry previousInteriorRing = null;
171
      if (m_iType == BUFFER_INSIDE_POLY) {
172
         //if we have radial internal buffers, we start by
173
         //most interior buffer
174
         for (int i = m_iRings; i >= 1; i--) {
175
            final double distRing = i * bufferDistance;
176
            final BufferOp bufOp = new BufferOp(inputParam);
177
            bufOp.setEndCapStyle(cap);
178
            final Geometry newGeometry = bufOp.getResultGeometry(-1 * distRing);
179
            if (verifyNilGeometry(newGeometry)) {
180
               //we have collapsed original geometry
181
               return;
182
            }
183
            if (previousInteriorRing != null) {
184
               solution = newGeometry.difference(previousInteriorRing);
185
            }
186
            else {
187
               solution = newGeometry;
188
            }
189
            numProcessed++;
190
            addFeature(solution, distRing, record);
191
            previousInteriorRing = newGeometry;
192
         }
193
      }
194
      else if (m_iType == BUFFER_OUTSIDE_POLY) {
195
         for (int i = 1; i <= m_iRings; i++) {
196
            final double distRing = i * bufferDistance;
197
            final BufferOp bufOp = new BufferOp(inputParam);
198
            bufOp.setEndCapStyle(cap);
199
            final Geometry newGeometry = bufOp.getResultGeometry(distRing);
200
            if (previousExteriorRing != null) {
201
               solution = newGeometry.difference(previousExteriorRing);
202
            }
203
            else {
204
               solution = newGeometry;
205
            }
206
            numProcessed++;
207
            addFeature(solution, distRing, record);
208
            previousExteriorRing = newGeometry;
209
         }
210
      }
211
      else if (m_iType == BUFFER_INSIDE_OUTSIDE_POLY) {
212
         final GeometryFactory geomFact = new GeometryFactory();
213
         for (int i = 1; i <= m_iRings; i++) {
214
            final double distRing = i * bufferDistance;
215
            final BufferOp bufOp = new BufferOp(inputParam);
216
            bufOp.setEndCapStyle(cap);
217
            final Geometry out = bufOp.getResultGeometry(distRing);
218
            final Geometry in = bufOp.getResultGeometry(-1 * distRing);
219
            boolean collapsedInterior = verifyNilGeometry(in);
220
            if ((previousExteriorRing == null) || (previousInteriorRing == null)) {
221
               if (collapsedInterior) {
222
                  solution = out;
223
               }
224
               else {
225
                  solution = out.difference(in);
226
               }
227
            }
228
            else {
229
               if (collapsedInterior) {
230
                  solution = out.difference(previousExteriorRing);
231
               }
232
               else {
233
                  final Geometry outRing = out.difference(previousExteriorRing);
234
                  final Geometry inRing = previousInteriorRing.difference(in);
235
                  final Geometry[] geomArray = new Geometry[] { outRing, inRing };
236
                  solution = geomFact.createGeometryCollection(geomArray);
237
                  final ArrayList polygons = new ArrayList();
238
                  final Stack stack = new Stack();
239
                  stack.push(solution);
240
                  while (stack.size() != 0) {
241
                     final GeometryCollection geCol = (GeometryCollection) stack.pop();
242
                     for (int j = 0; j < geCol.getNumGeometries(); j++) {
243
                        final Geometry geometry = geCol.getGeometryN(j);
244
                        if (geometry instanceof GeometryCollection) {
245
                           stack.push(geometry);
246
                        }
247
                        if (geometry instanceof Polygon) {
248
                           polygons.add(geometry);
249
                        }
250
                     }
251
                  }
252
                  final Polygon[] pols = new Polygon[polygons.size()];
253
                  polygons.toArray(pols);
254
                  final MultiPolygon newSolution = geomFact.createMultiPolygon(pols);
255
                  solution = newSolution;
256
               }
257
            }
258
            numProcessed++;
259
            addFeature(solution, -1 * distRing, distRing, record);
260
            previousExteriorRing = out;
261
            if (!collapsedInterior) {
262
               previousInteriorRing = in;
263
            }
264
         }
265
      }
266

    
267
   }
268

    
269

    
270
   protected void addFeature(final Geometry geom,
271
                             final double distance,
272
                             final Object[] record) {
273

    
274
      final Object[] values = new Object[2 + record.length];
275
      values[0] = new Long(numProcessed);
276
      values[1] = new Double(distance);
277
      for (int i = 0; i < record.length; i++) {
278
         values[i + 2] = record[i];
279
      }
280
      m_Output.addFeature(geom, values);
281

    
282
   }
283

    
284

    
285
   protected void addFeature(final Geometry geom,
286
                             final double distanceFrom,
287
                             final double distanceTo,
288
                             final Object[] record) {
289

    
290
      final Object[] values = new Object[3 + record.length];
291
      values[0] = new Long(numProcessed);
292
      values[1] = new Double(distanceFrom);
293
      values[2] = new Double(distanceTo);
294
      for (int i = 0; i < record.length; i++) {
295
         values[i + 3] = record[i];
296
      }
297
      m_Output.addFeature(geom, values);
298

    
299
   }
300

    
301

    
302
   public boolean verifyNilGeometry(final Geometry newGeometry) {
303

    
304
      if (newGeometry instanceof GeometryCollection) {
305
         if (((GeometryCollection) newGeometry).getNumGeometries() == 0) {
306
            //we have collapsed initial geometry
307
            return true;
308
         }
309
      }
310
      return false;
311
   }
312

    
313

    
314
}