Revision 254

View differences:

org.gvsig.toolbox/trunk/org.gvsig.toolbox/org.gvsig.toolbox.algorithm/src/main/java/es/unex/sextante/vectorTools/fixedDistanceBuffer/FixedDistanceBufferAlgorithm.java
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
}
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] = checkAttrName(layerIn.getFieldName(i), i + 3, sFieldNames);
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] = checkAttrName(layerIn.getFieldName(i), i + 2, sFieldNames);
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
}
org.gvsig.toolbox/trunk/org.gvsig.toolbox/org.gvsig.toolbox.algorithm/src/main/java/es/unex/sextante/vectorTools/variableDistanceBuffer/VariableDistanceBufferAlgorithm.java
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
}
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] = checkAttrName(layerIn.getFieldName(i), i + 3, sFieldNames);
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] = checkAttrName(layerIn.getFieldName(i), i + 2, sFieldNames);
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
}
org.gvsig.toolbox/trunk/org.gvsig.toolbox/org.gvsig.toolbox.algorithm/src/main/java/es/unex/sextante/vectorTools/distanceTableBuffer/DistanceTableBufferAlgorithm.java
1

  
2

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

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

  
8
import com.vividsolutions.jts.geom.Geometry;
9
import com.vividsolutions.jts.operation.buffer.BufferOp;
10

  
11
import es.unex.sextante.additionalInfo.AdditionalInfoVectorLayer;
12
import es.unex.sextante.core.GeoAlgorithm;
13
import es.unex.sextante.core.Sextante;
14
import es.unex.sextante.dataObjects.IFeature;
15
import es.unex.sextante.dataObjects.IFeatureIterator;
16
import es.unex.sextante.dataObjects.IVectorLayer;
17
import es.unex.sextante.dataObjects.vectorFilters.BoundingBoxFilter;
18
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
19
import es.unex.sextante.exceptions.RepeatedParameterNameException;
20
import es.unex.sextante.outputs.OutputVectorLayer;
21
import es.unex.sextante.parameters.FixedTableModel;
22

  
23

  
24
public class DistanceTableBufferAlgorithm
25
         extends
26
            GeoAlgorithm {
27

  
28

  
29
   public static final String RESULT          = "RESULT";
30
   public static final String NOTROUNDED      = "NOTROUNDED";
31
   public static final String LAYER           = "LAYER";
32
   public static final String DISTANCES       = "DISTANCES";
33

  
34
   private IVectorLayer       m_Output;
35
   private boolean            m_bRounded;
36
   private int                m_iNumProcessed = 0;
37
   private Double[]           m_Distances;
38

  
39

  
40
   @Override
41
   public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
42

  
43
      final IVectorLayer layerIn = m_Parameters.getParameterValueAsVectorLayer(LAYER);
44
      if (!m_bIsAutoExtent) {
45
         layerIn.addFilter(new BoundingBoxFilter(m_AnalysisExtent));
46
      }
47

  
48
      final FixedTableModel distances = (FixedTableModel) m_Parameters.getParameterValueAsObject(DISTANCES);
49
      final ArrayList<Double> distancesList = new ArrayList<Double>();
50
      for (int i = 0; i < distances.getRowCount(); i++) {
51
         try {
52
            final double dDistance = Double.parseDouble(distances.getValueAt(i, 0).toString());
53
            if (dDistance > 0) {
54
               distancesList.add(new Double(dDistance));
55
            }
56
         }
57
         catch (final Exception e) {
58
            //ignore wrong values in table
59
         }
60
      }
61

  
62
      if (distancesList.size() == 0) {
63
         throw new GeoAlgorithmExecutionException(Sextante.getText("No_Elements_In_Distance_List"));
64
      }
65

  
66
      m_Distances = distancesList.toArray(new Double[0]);
67
      Arrays.sort(m_Distances);
68

  
69
      m_bRounded = !m_Parameters.getParameterValueAsBoolean(NOTROUNDED);
70

  
71
      final int iFieldCount = layerIn.getFieldCount();
72
      Class types[];
73
      String[] sFieldNames;
74

  
75
      types = new Class[iFieldCount + 2];
76
      types[0] = Integer.class;
77
      types[1] = Double.class;
78
      sFieldNames = new String[iFieldCount + 2];
79
      sFieldNames[0] = "ID";
80
      sFieldNames[1] = "DIST";
81
      for (int i = 0; i < iFieldCount; i++) {
82
         sFieldNames[i + 2] = layerIn.getFieldName(i);
83
         types[i + 2] = layerIn.getFieldType(i);
84
      }
85

  
86
      m_Output = getNewVectorLayer(RESULT, "Buffer", IVectorLayer.SHAPE_TYPE_POLYGON, types, sFieldNames);
87

  
88
      int i = 0;
89
      final int iTotal = layerIn.getShapesCount();
90
      final IFeatureIterator iter = layerIn.iterator();
91
      while (iter.hasNext() && setProgress(i, iTotal)) {
92
         final IFeature feature = iter.next();
93
         computeBuffer(feature.getGeometry(), feature.getRecord().getValues());
94
         i++;
95
      }
96
      iter.close();
97

  
98
      return !m_Task.isCanceled();
99

  
100
   }
101

  
102

  
103
   @Override
104
   public void defineCharacteristics() {
105

  
106
      setName(Sextante.getText("Multiple_buffer"));
107
      setGroup(Sextante.getText("Buffers"));
108
      setUserCanDefineAnalysisExtent(true);
109

  
110
      try {
111
         m_Parameters.addInputVectorLayer(LAYER, Sextante.getText("Input_layer"), AdditionalInfoVectorLayer.SHAPE_TYPE_ANY, true);
112
         m_Parameters.addFixedTable(DISTANCES, Sextante.getText("Distances_table"),
113
                  new String[] { Sextante.getText("Distance") }, 3, false);
114
         m_Parameters.addBoolean(NOTROUNDED, Sextante.getText("Do_not_round_resulting_polygons"), false);
115

  
116
         addOutputVectorLayer(RESULT, Sextante.getText("Buffer"), OutputVectorLayer.SHAPE_TYPE_POLYGON);
117
      }
118
      catch (final RepeatedParameterNameException e) {
119
         Sextante.addErrorToLog(e);
120
      }
121

  
122
   }
123

  
124

  
125
   public void computeBuffer(final Geometry originalGeometry,
126
                             final Object[] record) {
127

  
128
      Geometry solution = null;
129
      final Geometry inputParam = originalGeometry;
130

  
131
      int cap = BufferOp.CAP_ROUND;
132
      if (!m_bRounded) {
133
         cap = BufferOp.CAP_SQUARE;
134
      }
135

  
136
      Geometry previousExteriorRing = null;
137
      for (int i = 0; i < m_Distances.length; i++) {
138
         final double dDistRing = m_Distances[i].doubleValue();
139
         final BufferOp bufOp = new BufferOp(inputParam);
140
         bufOp.setEndCapStyle(cap);
141
         final Geometry newGeometry = bufOp.getResultGeometry(dDistRing);
142
         if (previousExteriorRing != null) {
143
            solution = newGeometry.difference(previousExteriorRing);
144
         }
145
         else {
146
            solution = newGeometry;
147
         }
148
         m_iNumProcessed++;
149
         addFeature(solution, dDistRing, record);
150
         previousExteriorRing = newGeometry;
151
      }
152

  
153
   }
154

  
155

  
156
   protected void addFeature(final Geometry geom,
157
                             final double dDistance,
158
                             final Object[] record) {
159

  
160
      final Object[] values = new Object[2 + record.length];
161
      values[0] = new Long(m_iNumProcessed);
162
      values[1] = new Double(dDistance);
163
      for (int i = 0; i < record.length; i++) {
164
         values[i + 2] = record[i];
165
      }
166
      m_Output.addFeature(geom, values);
167

  
168
   }
169

  
170
}
1

  
2

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

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

  
8
import com.vividsolutions.jts.geom.Geometry;
9
import com.vividsolutions.jts.operation.buffer.BufferOp;
10

  
11
import es.unex.sextante.additionalInfo.AdditionalInfoVectorLayer;
12
import es.unex.sextante.core.GeoAlgorithm;
13
import es.unex.sextante.core.Sextante;
14
import es.unex.sextante.dataObjects.IFeature;
15
import es.unex.sextante.dataObjects.IFeatureIterator;
16
import es.unex.sextante.dataObjects.IVectorLayer;
17
import es.unex.sextante.dataObjects.vectorFilters.BoundingBoxFilter;
18
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
19
import es.unex.sextante.exceptions.RepeatedParameterNameException;
20
import es.unex.sextante.outputs.OutputVectorLayer;
21
import es.unex.sextante.parameters.FixedTableModel;
22

  
23

  
24
public class DistanceTableBufferAlgorithm
25
         extends
26
            GeoAlgorithm {
27

  
28

  
29
   public static final String RESULT          = "RESULT";
30
   public static final String NOTROUNDED      = "NOTROUNDED";
31
   public static final String LAYER           = "LAYER";
32
   public static final String DISTANCES       = "DISTANCES";
33

  
34
   private IVectorLayer       m_Output;
35
   private boolean            m_bRounded;
36
   private int                m_iNumProcessed = 0;
37
   private Double[]           m_Distances;
38

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff