Statistics
| Revision:

gvsig-geoprocess / org.gvsig.geoprocess / trunk / org.gvsig.geoprocess / org.gvsig.geoprocess.algorithm / org.gvsig.geoprocess.algorithm.buffer / src / main / java / org / gvsig / geoprocess / algorithm / buffer / BufferAlgorithm.java @ 1105

History | View | Annotate | Download (18.9 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2012 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.geoprocess.algorithm.buffer;
25

    
26
import java.io.File;
27

    
28
import javax.swing.JOptionPane;
29

    
30
import org.cresques.cts.IProjection;
31
import org.gvsig.fmap.dal.DALLocator;
32
import org.gvsig.fmap.dal.DataManager;
33
import org.gvsig.fmap.dal.DataStoreParameters;
34
import org.gvsig.fmap.dal.DataTypes;
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.exception.InitializeException;
37
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
38
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
39
import org.gvsig.fmap.dal.feature.EditableFeatureType;
40
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
41
import org.gvsig.fmap.dal.feature.FeatureStore;
42
import org.gvsig.fmap.dal.feature.FeatureType;
43
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
44
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
45
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
46
import org.gvsig.fmap.geom.Geometry;
47
import org.gvsig.geoprocess.lib.api.GeoProcessLocator;
48
import org.gvsig.geoprocess.lib.sextante.AbstractSextanteGeoProcess;
49
import org.gvsig.geoprocess.lib.sextante.dataObjects.FlyrVectIVectorLayer;
50

    
51
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
52
import es.unex.sextante.core.Sextante;
53
import es.unex.sextante.dataObjects.IVectorLayer;
54
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
55
import es.unex.sextante.exceptions.NullParameterValueException;
56
import es.unex.sextante.exceptions.OptionalParentParameterException;
57
import es.unex.sextante.exceptions.RepeatedParameterNameException;
58
import es.unex.sextante.exceptions.UndefinedParentParameterNameException;
59
import es.unex.sextante.exceptions.UnsupportedOutputChannelException;
60
import es.unex.sextante.exceptions.WrongParameterIDException;
61
import es.unex.sextante.exceptions.WrongParameterTypeException;
62
import es.unex.sextante.gui.algorithm.GeoAlgorithmParametersPanel;
63
import es.unex.sextante.outputs.OutputVectorLayer;
64

    
65
/**
66
 * Geoprocess that computes a buffer area around each feature's geometry of the
67
 * input layer. <br>
68
 * All the points interior to this buffer area has to be at a distance inferior
69
 * to "buffer distance" to the original geometry. This buffer distance could be
70
 * constant, or it could be a function of the value of a feature attribute.<br>
71
 * 
72
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
73
 * @author gvSIG Team
74
 */
75
public class BufferAlgorithm extends AbstractSextanteGeoProcess {
76

    
77
    public static final String RESULT                   = "RESULT";
78
    public static final String LAYER                    = "LAYER";
79
    public static final String SELECTED_GEOM            = "SELECTED_GEOM";
80
    public static final String DISTANCE                 = "DISTANCE";
81
    public static final String FIELD                    = "FIELD";
82
    public static final String DISSOLVE                 = "DISSOLVE";
83
    public static final String ROUND_BORDER             = "ROUND_BORDER";
84
    public static final String AREA                     = "AREA";
85
    public static final String RING_NUMBER              = "RING_NUMBER";
86
    
87
        /**
88
         * For polygonal buffers, only compute exterior buffers
89
         * (is the default operation, it applies to any geometry type)
90
         */
91
        public static final byte BUFFER_OUTSIDE_POLY        = 0;
92
        /**
93
         * For polygonal buffers, only compute interior buffers
94
         */
95
        public static final byte BUFFER_INSIDE_POLY         = 1;
96
        /**
97
         * For polygonal buffers, compute interior and exterior buffers
98
         */
99
        public static final byte BUFFER_INSIDE_OUTSIDE_POLY = 2;
100
        
101
    public static final byte SOURCE_FIELDS              = 0;
102
    public static final byte FID_DIST_FIELDS            = 1;
103
    public static final byte FID_FROM_TO_FIELDS         = 2;
104
    protected byte           tableFields                = -1; 
105
    
106
    private int              inflArea                   = BUFFER_OUTSIDE_POLY;
107
    protected boolean        dissolve                   = false;
108
    protected int            rings                      = 0;
109
    protected boolean        selectedGeom               = false;
110
    protected FeatureStore   inputStore                 = null;
111
    protected FeatureStore   outputStore                = null;
112
    protected IVectorLayer   sextanteInputLayer         = null;
113
    protected boolean        round_border               = false; 
114
        
115
    public static String[] sOptions = {
116
            GeoProcessLocator.getGeoProcessManager().getTranslation("poly_out"), 
117
            GeoProcessLocator.getGeoProcessManager().getTranslation("poly_in"),
118
            GeoProcessLocator.getGeoProcessManager().getTranslation("poly_inandout") 
119
    };
120

    
121
    public void defineCharacteristics() {
122
        setName(getTranslation("Buffer"));
123
        setGroup(getTranslation("basic_vect_algorithms"));
124
        // setGeneratesUserDefinedRasterOutput(false);
125
       
126
        try {
127
            m_Parameters.addInputVectorLayer(LAYER, getTranslation("Input_layer"), 
128
                    IVectorLayer.SHAPE_TYPE_WRONG, true);
129
            m_Parameters.addBoolean(SELECTED_GEOM, getTranslation("Selected_geometries"), false);
130
            m_Parameters.addNumericalValue(DISTANCE, getTranslation("area_distance"), 0,
131
                AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE);
132
            m_Parameters.addTableField(FIELD, getTranslation("area_field"), "LAYER");
133
            m_Parameters.addBoolean(DISSOLVE, getTranslation("Dissolve_entities"), false);
134
            m_Parameters.addBoolean(ROUND_BORDER, getTranslation("Round_border"), true);
135
            m_Parameters.addSelection(AREA, getTranslation("Builds_influence_area"), sOptions);
136
            m_Parameters.addSelection(RING_NUMBER, getTranslation("Number_of_rings"),
137
                new String[] { "1", "2", "3" });
138
        } catch (RepeatedParameterNameException e) {
139
            Sextante.addErrorToLog(e);
140
        } catch (UndefinedParentParameterNameException e) {
141
            Sextante.addErrorToLog(e);
142
        } catch (OptionalParentParameterException e) {
143
            Sextante.addErrorToLog(e);
144
        }
145
        addOutputVectorLayer(RESULT, getTranslation("Buffer"),
146
            OutputVectorLayer.SHAPE_TYPE_POLYGON);
147
    }
148
    
149
    protected void readParameters() throws WrongParameterTypeException, NullParameterValueException, WrongParameterIDException {
150
            sextanteInputLayer = m_Parameters.getParameterValueAsVectorLayer(LAYER);
151
            selectedGeom = m_Parameters.getParameter(SELECTED_GEOM).getParameterValueAsBoolean();
152
            rings = m_Parameters.getParameterValueAsInt(RING_NUMBER);
153
        dissolve = m_Parameters.getParameter(DISSOLVE).getParameterValueAsBoolean();
154
        round_border = m_Parameters.getParameter(ROUND_BORDER).getParameterValueAsBoolean();
155
    }
156

    
157
    public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
158
            if(existsOutPutFile(BufferAlgorithm.RESULT, 0)) {
159
                    throw new GeoAlgorithmExecutionException(getTranslation("file_exists"));
160
            }
161
        
162
        double distanceValue = m_Parameters.getParameter(DISTANCE).getParameterValueAsDouble();
163
        String attributeName = m_Parameters.getParameterValueAsString(FIELD);
164
        inflArea = m_Parameters.getParameterValueAsInt(AREA);
165
        readParameters();
166

    
167
        if (sextanteInputLayer.getShapeType() != IVectorLayer.SHAPE_TYPE_POLYGON
168
            && inflArea != BUFFER_OUTSIDE_POLY) {
169
            JOptionPane.showMessageDialog(null,
170
                getTranslation("Wrong_type_for_this_shapetype"), "Error",
171
                JOptionPane.WARNING_MESSAGE);
172
            inflArea = BUFFER_OUTSIDE_POLY;
173
        }
174
        
175
        if (sextanteInputLayer instanceof FlyrVectIVectorLayer)
176
            inputStore = ((FlyrVectIVectorLayer) sextanteInputLayer).getFeatureStore();
177
        else
178
            return false;
179
        
180

    
181
        try {
182
            // Object to compute the distance
183
            IDistance distance = null;
184
            if (distanceValue == 0) {
185
                //int featureAttributePosition = ((FlyrVectIVectorLayer) sextanteInputLayer).getFeatureIndexByFieldIndex(attributePosition);
186
                distance = new FieldDistance(attributeName);//featureAttributePosition);
187
            } else {
188
                distance = new ConstantDistance(distanceValue);
189
            }
190
            // Object to compute the buffer operation
191
            BufferOperation operation = null;
192
            switch (inflArea) {
193
            case BUFFER_OUTSIDE_POLY:
194
                operation = new OutBufferOperation(distance, inputStore, this, getTableFieldsStructure());
195
                break;
196
            case BUFFER_INSIDE_POLY:
197
                operation = new InBufferOperation(distance, inputStore, this, getTableFieldsStructure());
198
                break;
199
            case BUFFER_INSIDE_OUTSIDE_POLY:
200
                operation = new InOutBufferOperation(distance, inputStore, this, getTableFieldsStructure());
201
                break;
202
            }
203
            operation.setTypeOfCap(round_border ? BufferOperation.CAP_ROUND : BufferOperation.CAP_SQUARE);
204
            operation.setGeoProcess(this, 100);
205
            
206
                // Builds the output FeatureStore
207
            outputStore = buildOutPutStore(IVectorLayer.SHAPE_TYPE_POLYGON,
208
                                                getTranslation("Buffer"), RESULT);
209
                
210
                if(!dissolve) {
211
                        computesBufferAlgWithoutDissolve(operation);
212
                } else {
213
                        computesBufferAlgWithDissolve(operation);
214
                }
215
                
216
        } catch (DataException e) {
217
            Sextante.addErrorToLog(e);
218
            return false;
219
        }
220
        
221
                if(getTaskMonitor().isCanceled())
222
                        return false;
223

    
224
        return true;
225
    }
226
    
227
    private void computesOneRingBufferWithDissolve(
228
                    BufferOperation operation, 
229
                    FuseOperation fuseOp, 
230
                    String idFile,
231
                    int initialPosition,
232
                    int ringPosition) throws ValidateDataParametersException, DataException {
233
            String file = System.getProperty("java.io.tmpdir") + File.separator + (idFile) + ".shp";
234
                FeatureStore outAuxFeatStore = buildTemporalStore(org.gvsig.fmap.geom.Geometry.TYPES.SURFACE, file, 
235
                                inputStore.getDefaultFeatureType().getDefaultSRS());
236
                
237
                operation.getDistance().setNumberOfRings(ringPosition + 1);
238
                
239
                operation.setNumberOfRadialBuffers(1);
240
                operation.setTaskStatus(getStatus());
241
                m_Task.setProgressText(getTranslation("calc_buffer") + " [Ring:" + (rings - ringPosition) + "]");
242
                operation.computesGeometryOperation(inputStore, outAuxFeatStore,
243
                                attrNames, selectedGeom, false, true);
244
                
245
                outAuxFeatStore = open(file, inputStore.getDefaultFeatureType().getDefaultSRS());
246
                
247
                m_Task.setProgressText(getTranslation("fuse_spatially") + " [Ring:" + (rings - ringPosition) + "]");
248
                fuseOp.computesGeometryOperation(outAuxFeatStore, outputStore, attrNames, ringPosition == initialPosition ? true : false);
249
                outAuxFeatStore.dispose();
250
    }
251
    
252
    protected void computesBufferAlgWithDissolve(BufferOperation operation) throws DataException {
253
            long fileTmpId = System.currentTimeMillis();
254
            FuseOperation fuseOp = new FuseOperation(this);
255
            
256
            if(inflArea == BUFFER_OUTSIDE_POLY || inflArea == BUFFER_INSIDE_OUTSIDE_POLY) {
257
                    try {
258
                            for (int i = rings; i >= 0 ; i--) {
259
                                    computesOneRingBufferWithDissolve(
260
                                                    operation, 
261
                                                    fuseOp, 
262
                                                    fileTmpId + i + "",
263
                                                    rings,
264
                                                    i);
265
                            }
266
                    } catch (ValidateDataParametersException e) {
267
                            Sextante.addErrorToLog(e);
268
                    }
269
            }
270
            
271
            if(inflArea == BUFFER_INSIDE_POLY) {
272
                    try {
273
                            for (int i = 0; i < rings + 1 ; i++) {
274
                                    computesOneRingBufferWithDissolve(
275
                                                    operation, 
276
                                                    fuseOp, 
277
                                                    fileTmpId + i + "",
278
                                                    0,
279
                                                    i);
280
                            }
281
                    } catch (ValidateDataParametersException e) {
282
                            Sextante.addErrorToLog(e);
283
                    }
284
            }
285
            
286
            fuseOp.end();
287
    }
288
    
289
    protected void computesBufferAlgWithoutDissolve(BufferOperation operation) throws DataException {
290
            operation.setNumberOfRadialBuffers(rings + 1);
291
            operation.setTaskStatus(getStatus());
292
            operation.computesGeometryOperation(inputStore, 
293
                            outputStore,
294
                            attrNames, 
295
                            selectedGeom, 
296
                            false, 
297
                            true);
298
    }
299
    
300
    
301
    /**
302
     * Gets the constant with the table structure 
303
     * @return
304
     */
305
    protected byte getTableFieldsStructure() {
306
            if(tableFields == -1) {
307
            if(!dissolve) {
308
                    tableFields = SOURCE_FIELDS;
309
                } else {
310
                if (inflArea == BUFFER_INSIDE_OUTSIDE_POLY) 
311
                        tableFields = FID_FROM_TO_FIELDS;
312
                else
313
                        tableFields = FID_DIST_FIELDS;
314
                }
315
            }
316
            return tableFields;
317
    }
318
    
319
    /**
320
     * Open a <code>DataStore</code>
321
     * @param file
322
     * @param proj
323
     * @return
324
     * @throws InitializeException
325
     * @throws ProviderNotRegisteredException
326
     * @throws ValidateDataParametersException
327
     */
328
    private FeatureStore open(String file, IProjection proj) throws InitializeException, ProviderNotRegisteredException, ValidateDataParametersException {
329
            DataManager manager = DALLocator.getDataManager();
330
            DataStoreParameters params = manager.createStoreParameters("Shape");
331
            params.setDynValue("shpfile", file);
332
            params.setDynValue("crs", proj);
333
            FeatureStore featureStore = (FeatureStore) manager.openStore(params.getDataStoreName(), params);
334
            return featureStore;
335
    }
336

    
337
    /**
338
     * Builds the output FeatureStore
339
     * 
340
     * @param featureType
341
     * @return FeatureStore
342
     * @throws DataException 
343
     */
344
    protected FeatureStore buildOutPutStore(int shapeType, 
345
                    String sextanteLayerName, 
346
                    String sextanteLayerLabel) throws DataException {
347
            FeatureType featureType = inputStore.getDefaultFeatureType();
348
            
349
            if(getTableFieldsStructure() == SOURCE_FIELDS) {
350
                    return super.buildOutPutStore(featureType, shapeType,sextanteLayerName, sextanteLayerLabel);
351
            } 
352
            Class<?>[] types = null;
353
            if (getTableFieldsStructure() == FID_FROM_TO_FIELDS) {
354
                    types = new Class[] { Integer.class, Double.class, Double.class };
355
                    attrNames = new String[] { "FID", "FROM", "TO" };
356
            } 
357
            if (getTableFieldsStructure() == FID_DIST_FIELDS) {
358
                    types = new Class[] { Integer.class, Double.class };
359
                    attrNames = new String[] { "FID", "DIST" };
360
            }
361
            try {
362
                    IVectorLayer output =
363
                                    getNewVectorLayer(sextanteLayerLabel, sextanteLayerName,
364
                                                    shapeType, types, attrNames);
365
                    return ((FlyrVectIVectorLayer) output).getFeatureStore();
366
            } catch (UnsupportedOutputChannelException e) {
367
                    Sextante.addErrorToLog(e);
368
            } catch (GeoAlgorithmExecutionException e) {
369
                    Sextante.addErrorToLog(e);
370
            }
371
            
372
            return null;
373
    }
374

    
375
    /**
376
     * Builds the output FeatureStore
377
     * 
378
     * @param featureType
379
     * @return FeatureStore
380
     * @throws DataException 
381
     * @throws ValidateDataParametersException 
382
     */
383
    protected FeatureStore buildTemporalStore(int shapeType, 
384
                    String file, 
385
                    IProjection crs) throws DataException, ValidateDataParametersException {
386
            FeatureType featureType = inputStore.getDefaultFeatureType();
387
            
388
        int[] types = null;
389
        if(getTableFieldsStructure() == SOURCE_FIELDS) {
390
                FeatureAttributeDescriptor[] desc = featureType.getAttributeDescriptors();
391
                types = new int[desc.length - 1];
392
                attrNames = new String[desc.length - 1];
393
                int attrCount = 0;
394
                for (int i = 0; i < desc.length; i++) {
395
                        if(desc[i].getType() != DataTypes.GEOMETRY) {
396
                                types[attrCount] = desc[i].getType();
397
                                attrNames[attrCount] = desc[i].getName();
398
                                attrCount ++;
399
                        }
400
                        }
401
        }
402
        if (getTableFieldsStructure() == FID_FROM_TO_FIELDS) {
403
            types = new int[] { java.sql.Types.INTEGER, java.sql.Types.DOUBLE, java.sql.Types.DOUBLE };
404
            attrNames = new String[] { "FID", "FROM", "TO" };
405
        }
406
        if (getTableFieldsStructure() == FID_DIST_FIELDS) {
407
            types = new int[] { java.sql.Types.INTEGER, java.sql.Types.DOUBLE };
408
            attrNames = new String[] { "FID", "DIST" };
409
        }
410

    
411
        return create(file, types, attrNames, crs);
412
    }
413
    
414
        @SuppressWarnings("deprecation")
415
        public FeatureStore create(String sFilename,
416
                        int[] types, String[] attrNames, IProjection crs) {
417
                try {
418
                        DataManager manager = DALLocator.getDataManager();
419
                        FilesystemServerExplorerParameters explorerParams =
420
                            (FilesystemServerExplorerParameters) manager.createServerExplorerParameters("FilesystemExplorer");
421
                        explorerParams.setRoot(new File(sFilename).getParent());
422
                        FilesystemServerExplorer explorer = (FilesystemServerExplorer) manager.createServerExplorer(explorerParams);
423
                        NewFeatureStoreParameters newParams = (NewFeatureStoreParameters) explorer.getAddParameters(new File(sFilename));
424
                        
425
                        EditableFeatureType ft = newParams.getDefaultFeatureType();
426
                        for (int i = 0; i < attrNames.length; i++) {
427
                                ft.add(attrNames[i], types[i], 7);
428
                        }
429
                        ft.add("GEOMETRY", DataTypes.GEOMETRY).setGeometryType(
430
                                        Geometry.TYPES.SURFACE).setGeometrySubType(Geometry.SUBTYPES.GEOM2D);
431
                        
432
                        newParams.setDefaultFeatureType(ft);
433
                        newParams.setDynValue("CRS", crs);
434
                        newParams.setDynValue("geometryType", Geometry.TYPES.SURFACE);
435

    
436
                        manager.newStore("FilesystemExplorer",
437
                newParams.getDataStoreName(), newParams, true);
438
                
439
                        FeatureStore featureStore = (FeatureStore) manager.openStore(newParams.getDataStoreName(), newParams);                        
440
                        featureStore.edit(FeatureStore.MODE_APPEND);
441
                        return featureStore;
442
                } catch (Exception e) {
443
                        Sextante.addErrorToLog(e);
444
                }
445
                return null;
446
        }
447

    
448

    
449
    @Override
450
    public Class<? extends GeoAlgorithmParametersPanel> getCustomParametersPanelClass() {
451
        return BufferParametersPanel.class;
452
    }
453
}