Statistics
| Revision:

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

History | View | Annotate | Download (12.6 KB)

1

    
2

    
3
package es.unex.sextante.vectorTools.variableDistanceBuffer;
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.AdditionalInfoVectorLayer;
17
import es.unex.sextante.core.GeoAlgorithm;
18
import es.unex.sextante.core.Sextante;
19
import es.unex.sextante.dataObjects.IFeature;
20
import es.unex.sextante.dataObjects.IFeatureIterator;
21
import es.unex.sextante.dataObjects.IVectorLayer;
22
import es.unex.sextante.dataObjects.vectorFilters.BoundingBoxFilter;
23
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
24
import es.unex.sextante.exceptions.OptionalParentParameterException;
25
import es.unex.sextante.exceptions.RepeatedParameterNameException;
26
import es.unex.sextante.exceptions.UndefinedParentParameterNameException;
27
import es.unex.sextante.outputs.OutputVectorLayer;
28

    
29

    
30
public class VariableDistanceBufferAlgorithm
31
         extends
32
            GeoAlgorithm {
33

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

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

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

    
51

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

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

    
61
      m_bRounded = !m_Parameters.getParameterValueAsBoolean(NOTROUNDED);
62
      m_iRings = m_Parameters.getParameterValueAsInt(RINGS) + 1;
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
      double dDistance;
104
      final IFeatureIterator iter = layerIn.iterator();
105
      while (iter.hasNext() && setProgress(i, iTotal)) {
106
         final IFeature feature = iter.next();
107
         try {
108

    
109
            final Number num = (Number) feature.getRecord().getValue(iField);
110
            dDistance = num.doubleValue();
111
         }
112
         catch (final Exception e) {
113
            continue;
114
         }
115
         computeBuffer(feature.getGeometry(), dDistance, feature.getRecord().getValues());
116
         i++;
117
      }
118
      iter.close();
119

    
120
      return !m_Task.isCanceled();
121

    
122
   }
123

    
124

    
125
   @Override
126
   public void defineCharacteristics() {
127

    
128
      final String[] sRings = { Integer.toString(1), Integer.toString(2), Integer.toString(3) };
129
      final String[] sType = { Sextante.getText("Outer_buffer"), Sextante.getText("Inner_buffer"), Sextante.getText("Both"), };
130

    
131
      setName(Sextante.getText("Variable_distance_buffer"));
132
      setGroup(Sextante.getText("Buffers"));
133
      setUserCanDefineAnalysisExtent(true);
134

    
135
      try {
136
         m_Parameters.addInputVectorLayer(LAYER, Sextante.getText("Input_layer"), AdditionalInfoVectorLayer.SHAPE_TYPE_ANY, true);
137
         m_Parameters.addTableField(FIELD, Sextante.getText("Distance_field"), "LAYER");
138
         m_Parameters.addSelection(TYPE, Sextante.getText("Buffer_type"), sType);
139
         m_Parameters.addSelection(RINGS, Sextante.getText("Number_of_concentric_rings"), sRings);
140
         m_Parameters.addBoolean(NOTROUNDED, Sextante.getText("Do_not_round_resulting_polygons"), false);
141

    
142
         addOutputVectorLayer(RESULT, Sextante.getText("Buffer"), OutputVectorLayer.SHAPE_TYPE_POLYGON);
143
      }
144
      catch (final RepeatedParameterNameException e) {
145
         Sextante.addErrorToLog(e);
146
      }
147
      catch (final UndefinedParentParameterNameException e) {
148
         Sextante.addErrorToLog(e);
149
      }
150
      catch (final OptionalParentParameterException e) {
151
         Sextante.addErrorToLog(e);
152
      }
153

    
154
   }
155

    
156

    
157
   //*********** code adapted from BufferVisitor class, by Alvaro Zabala*******************//
158

    
159
   public void computeBuffer(final Geometry originalGeometry,
160
                             final double bufferDistance,
161
                             final Object[] record) {
162
      Geometry solution = null;
163
      Geometry inputParam = originalGeometry;
164
      /*
165
       * When we try to apply large buffer distances, we could get OutOfMemoryError
166
       * exceptions. Explanation in
167
       * http://lists.jump-project.org/pipermail/jts-devel/2005-February/000991.html
168
       * http://lists.jump-project.org/pipermail/jts-devel/2005-September/001292.html
169
       * This problems hasnt been resolved in JTS 1.7.
170
       */
171
      if (originalGeometry.getDimension() != 0) {
172
         inputParam = TopologyPreservingSimplifier.simplify(originalGeometry, bufferDistance / 10d);
173
      }
174
      int cap = BufferOp.CAP_ROUND;
175
      if (!m_bRounded) {
176
         cap = BufferOp.CAP_SQUARE;
177
      }
178

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

    
278
   }
279

    
280

    
281
   protected void addFeature(final Geometry geom,
282
                             final double distance,
283
                             final Object[] record) {
284

    
285
      final Object[] values = new Object[2 + record.length];
286
      values[0] = new Long(numProcessed);
287
      values[1] = new Double(distance);
288
      for (int i = 0; i < record.length; i++) {
289
         values[i + 2] = record[i];
290
      }
291
      m_Output.addFeature(geom, values);
292

    
293
   }
294

    
295

    
296
   protected void addFeature(final Geometry geom,
297
                             final double distanceFrom,
298
                             final double distanceTo,
299
                             final Object[] record) {
300

    
301
      final Object[] values = new Object[3 + record.length];
302
      values[0] = new Long(numProcessed);
303
      values[1] = new Double(distanceFrom);
304
      values[2] = new Double(distanceTo);
305
      for (int i = 0; i < record.length; i++) {
306
         values[i + 3] = record[i];
307
      }
308
      m_Output.addFeature(geom, values);
309

    
310
   }
311

    
312

    
313
   public boolean verifyNilGeometry(final Geometry newGeometry) {
314

    
315
      if (newGeometry instanceof GeometryCollection) {
316
         if (((GeometryCollection) newGeometry).getNumGeometries() == 0) {
317
            //we have collapsed initial geometry
318
            return true;
319
         }
320
      }
321
      return false;
322
   }
323

    
324

    
325
}