Statistics
| Revision:

gvsig-geoprocess / org.gvsig.geoprocess / trunk / org.gvsig.geoprocess / org.gvsig.geoprocess.algorithm / org.gvsig.geoprocess.algorithm.groupby / src / main / java / org / gvsig / geoprocess / algorithm / groupby / GroupByAlgorithm.java @ 385

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.groupby;
25

    
26
import java.util.ArrayList;
27
import java.util.Date;
28
import java.util.HashMap;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.Set;
32

    
33
import org.gvsig.fmap.dal.DALLocator;
34
import org.gvsig.fmap.dal.DataManager;
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.feature.EditableFeature;
37
import org.gvsig.fmap.dal.feature.Feature;
38
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
39
import org.gvsig.fmap.dal.feature.FeatureQuery;
40
import org.gvsig.fmap.dal.feature.FeatureSet;
41
import org.gvsig.fmap.dal.feature.FeatureStore;
42
import org.gvsig.fmap.dal.feature.FeatureType;
43
import org.gvsig.fmap.geom.Geometry;
44
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
45
import org.gvsig.fmap.geom.Geometry.TYPES;
46
import org.gvsig.fmap.geom.aggregate.MultiCurve;
47
import org.gvsig.fmap.geom.aggregate.MultiPoint;
48
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
49
import org.gvsig.fmap.geom.aggregate.MultiSurface;
50
import org.gvsig.fmap.geom.exception.CreateGeometryException;
51
import org.gvsig.fmap.geom.primitive.Curve;
52
import org.gvsig.fmap.geom.primitive.Point;
53
import org.gvsig.fmap.geom.primitive.Surface;
54
import org.gvsig.geoprocess.algorithm.base.util.GeometryUtil;
55
import org.gvsig.geoprocess.algorithm.base.util.JTSFacade;
56
import org.gvsig.geoprocess.lib.sextante.AbstractSextanteGeoProcess;
57
import org.gvsig.geoprocess.lib.sextante.dataObjects.FlyrVectIVectorLayer;
58
import org.gvsig.timesupport.Instant;
59
import org.gvsig.tools.dispose.DisposableIterator;
60
import org.gvsig.tools.evaluator.Evaluator;
61

    
62
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
63
import es.unex.sextante.core.Sextante;
64
import es.unex.sextante.dataObjects.IVectorLayer;
65
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
66
import es.unex.sextante.exceptions.RepeatedParameterNameException;
67
import es.unex.sextante.exceptions.UnsupportedOutputChannelException;
68
import es.unex.sextante.gui.algorithm.GeoAlgorithmParametersPanel;
69
import es.unex.sextante.outputs.OutputVectorLayer;
70

    
71
/**
72
 * @author <a href="mailto:nachobrodin@gmail.com">Nacho Brodin</a>
73
 */
74
public class GroupByAlgorithm extends AbstractSextanteGeoProcess {
75

    
76
        public static final String         RESULT            = "RESULT";
77
        public static final String         LAYER             = "LAYER";
78
        public static final String         FIELD             = "FIELD";
79
        public static final String         FIELD_DATE        = "FIELD_DATE";
80
        public static final String         FIELD_LIST        = "FIELD_LIST";
81
        public static final String         LAYER_NAME        = "LAYER_NAME";
82
        /**
83
         * <P>Possible values</P>
84
         * <UL>
85
         * <LI>-1: Without geometry</LI>
86
         * <LI>0: First geometry </LI>
87
         * <LI>1: Creates a multigeometry </LI>
88
         * <LI>2: Fusion of polygons </LI>
89
         * </UL>
90
         **/
91
        public static final String         GEOM_OPTION       = "GEOM_OPTION";
92
        public static final String         FUNCTION_LIST     = "FUNCTION_LIST";
93
        public static final String         Summary[]         = {"Min", "Max", "Sum", "Avg", "Last", "Any"};
94
         
95
        /*
96
         * (non-Javadoc)
97
         * @see es.unex.sextante.core.GeoAlgorithm#defineCharacteristics()
98
         */
99
        public void defineCharacteristics(){
100
        setName(getTranslation("groupby"));
101
        setGroup(getTranslation("basic_vect_algorithms"));
102
        // setGeneratesUserDefinedRasterOutput(false);
103
                try {
104
                        m_Parameters.addInputVectorLayer(LAYER, getTranslation("Input_layer"), IVectorLayer.SHAPE_TYPE_WRONG, true);
105
                        m_Parameters.addString(FIELD, getTranslation("Field"));
106
                        m_Parameters.addString(FIELD_DATE, getTranslation("Field_date"));
107
                        m_Parameters.addString(FIELD_LIST, getTranslation("Field_list"));
108
                        m_Parameters.addString(FUNCTION_LIST, getTranslation("Function_list"));
109
                        m_Parameters.addString(LAYER_NAME, getTranslation("Layer_name"));
110
                        m_Parameters.addNumericalValue(GEOM_OPTION, getTranslation("Geom"), -1, AdditionalInfoNumericalValue.NUMERICAL_VALUE_INTEGER);
111
                        addOutputVectorLayer(RESULT, getTranslation("group_by"), OutputVectorLayer.SHAPE_TYPE_UNDEFINED);
112
                } catch (RepeatedParameterNameException e) {
113
                        Sextante.addErrorToLog(e);
114
                }
115
        }
116
        
117
        /*
118
         * (non-Javadoc)
119
         * @see es.unex.sextante.core.GeoAlgorithm#processAlgorithm()
120
         */
121
        public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
122
                if(existsOutPutFile(GroupByAlgorithm.RESULT, 0)) {
123
                    throw new GeoAlgorithmExecutionException(getTranslation("file_exists"));
124
            }
125
                IVectorLayer layer = m_Parameters.getParameterValueAsVectorLayer(LAYER);
126
                String groupByField = m_Parameters.getParameterValueAsString(FIELD);
127
                String fieldDate = m_Parameters.getParameterValueAsString(FIELD_DATE);
128
                String fieldsString = m_Parameters.getParameterValueAsString(FIELD_LIST);
129
                String functionsString = m_Parameters.getParameterValueAsString(FUNCTION_LIST);
130
                String layerName = m_Parameters.getParameterValueAsString(LAYER_NAME);
131
                int geomOption = m_Parameters.getParameterValueAsInt(GEOM_OPTION);
132
                int inputShapeType = layer.getShapeType();
133
                
134
                String[] funcList = functionsString.split(";");
135
                String[] fieldList = fieldsString.split(";");
136
                
137
                if(fieldList != null && funcList != null) {
138
                        if(fieldList.length != funcList.length) {
139
                                Sextante.addErrorToLog("invalid_input_parameters");
140
                        }
141
                }
142
                
143
                FeatureStore featureStore = null;
144
                if(layer instanceof FlyrVectIVectorLayer)
145
                        featureStore = ((FlyrVectIVectorLayer)layer).getFeatureStore();
146
                else
147
                        return false;
148
                
149
                try {
150
                        FeatureType featureType = featureStore.getDefaultFeatureType();
151
                        FeatureAttributeDescriptor desc = featureType.getAttributeDescriptor(groupByField);
152
                        String fieldNameGrouped = desc.getName();
153
                        FeatureStore outFeatStore = buildOutPutStore(featureType, 
154
                                                                                                                layerName, 
155
                                                                                                                groupByField, 
156
                                                                                                                fieldList, 
157
                                                                                                                funcList, 
158
                                                                                                                geomOption,
159
                                                                                                                inputShapeType);
160
                        
161
                        Set<String> list = getGroupedValues(featureStore, groupByField);
162
                        int numberOfFeatures = list.size();
163
                        if (getStatus() != null) {
164
                                getStatus().setRangeOfValues(0, numberOfFeatures);
165
                }
166
                        int cont = 0;
167
                        Iterator<String> it = list.iterator();
168
                        while( it.hasNext() ) {
169
                                if (getStatus() != null) {
170
                                        getStatus().setCurValue(cont);
171
                        }        
172
                                setProgress(cont, numberOfFeatures);
173
                                String groupedValue = it.next();
174
                                loadFeature(featureStore, 
175
                                                outFeatStore, 
176
                                                fieldNameGrouped, 
177
                                                fieldDate, 
178
                                                groupedValue, 
179
                                                fieldList, 
180
                                                funcList,
181
                                                geomOption);
182
                                cont++;
183
                        }
184
                        
185
                        outFeatStore.finishEditing();
186
                } catch (DataException e) {
187
                        Sextante.addErrorToLog(e);
188
                }
189
                
190
                return true;
191
        }
192
        
193
        private void loadFeature(FeatureStore inStore, 
194
                        FeatureStore outStore, 
195
                        String fieldNameGrouped,
196
                        String fieldDate,
197
                        String groupedValue, 
198
                        String[] fieldList, 
199
                        String[] funcList,
200
                        int geomOption) throws DataException {
201
                DataManager manager = DALLocator.getDataManager();
202
                
203
                EditableFeature feat = outStore.createNewFeature(outStore.getDefaultFeatureType(), true);
204

    
205
                FeatureQuery query = inStore.createFeatureQuery();
206
                Evaluator filter = manager.createExpresion(fieldNameGrouped + " = '" + groupedValue + "'");
207
                query.setFilter(filter);
208
                FeatureSet featSet = inStore.getFeatureSet(query);
209
                DisposableIterator it = featSet.iterator();
210
                List<Geometry> geomList = new ArrayList<Geometry>();
211
                
212
                Object[] values = null;
213
                if(fieldList != null)
214
                        values = new Object[fieldList.length];
215
                int nFeaturesByGroup = 0;
216
                Instant lastDate = null;
217

    
218
                while(it.hasNext()) {
219
                        Feature feature = (Feature)it.next();
220

    
221
                        if(fieldList != null) {
222
                                for (int i = 0; i < fieldList.length; i++) {
223
                                        Object v = feature.get(fieldList[i]);
224
                                        //Class<?> c = inStore.getDefaultFeatureType().getAttributeDescriptor(funcList[i]).getClassOfValue();
225
                                        if(v instanceof Number) {
226
                                                if(funcList[i].compareToIgnoreCase("Min") == 0) {
227
                                                        if(values[i] == null) 
228
                                                                values[i] = Double.POSITIVE_INFINITY;
229
                                                        values[i] = updateMinimum((Double)values[i], v);
230
                                                }
231
                                                if(funcList[i].compareToIgnoreCase("Max") == 0) {
232
                                                        if(values[i] == null) 
233
                                                                values[i] = Double.NEGATIVE_INFINITY;
234
                                                        values[i] = updateMaximum((Double)values[i], v);
235
                                                }
236
                                                if(funcList[i].compareToIgnoreCase("Sum") == 0 || funcList[i].compareToIgnoreCase("Average") == 0) {
237
                                                        if(values[i] == null) 
238
                                                                values[i] = new Double(0D);
239
                                                        values[i] = sum((Double)values[i], v);
240
                                                }
241
                                        }
242
                                        if(funcList[i].compareToIgnoreCase("First") == 0) {
243
                                                if(values[i] == null) 
244
                                                        values[i] = v;
245
                                        }
246
                                        if(funcList[i].compareToIgnoreCase("Last") == 0 && fieldDate != null) {
247
                                                if(lastDate == null || 
248
                                                                values[i] == null || 
249
                                                                lastDate.isAfter(feature.getInstant(fieldDate))) {
250
                                                        lastDate = feature.getInstant(fieldDate);
251
                                                        values[i] = v;
252
                                                }
253
                                        }
254
                                }
255
                        }
256
                        
257
                        if(geomOption >= 0) {
258
                                switch (geomOption) {
259
                                case 0: //Adds only the first geometry
260
                                        if(nFeaturesByGroup == 0) { //If is the first feature
261
                                                Geometry g = feature.getDefaultGeometry();
262
                                                if(!(g instanceof MultiPrimitive)) {
263
                                                        List<Geometry> gList = new ArrayList<Geometry>();
264
                                                        gList.add(g);
265
                                                        g = buildMultiGeometry(gList);
266
                                                }
267
                                                feat.set(outStore.getDefaultFeatureType().getDefaultGeometryAttributeName(), g);
268
                                        }
269
                                        break;
270
                                case 1: //Multigeometry with all geometries
271
                                case 2: //Union among all geometries
272
                                        geomList.add(feature.getDefaultGeometry().cloneGeometry());
273
                                        break;
274
                                }
275
                        }
276
                        nFeaturesByGroup ++;
277
                }
278

    
279
                it.dispose();
280
                featSet.dispose();
281
                feat.set(fieldNameGrouped, groupedValue);
282
                
283
                //Se asignan los campos calculados
284
                if(fieldList != null) {
285
                        for (int i = 0; i < values.length; i++) {
286
                                if(funcList[i].compareToIgnoreCase("Average") == 0) {
287
                                        values[i] = ((Double)values[i]).doubleValue() / nFeaturesByGroup; 
288
                                } 
289
                                feat.set(i + 1, values[i]);                                        
290
                        }
291
                }
292
                
293
                //Si hay que convertir a multigeometr?a
294
                if(geomOption == 1 && geomList.size() > 0)
295
                        feat.set(outStore.getDefaultFeatureType().getDefaultGeometryAttributeName(), buildMultiGeometry(geomList));
296
                if(geomOption == 2 && geomList.size() > 0)
297
                        feat.set(outStore.getDefaultFeatureType().getDefaultGeometryAttributeName(), computesUnion(geomList));
298
                outStore.update(feat);
299
        }
300
        
301
        /**
302
         * Builds a unique geometry with all geometries in the list
303
         * @param geomList
304
         * @return
305
         */
306
        private Geometry buildMultiGeometry(List<Geometry> geomList) {
307
                Geometry newGeom = null;
308
                for (int i = 0; i < geomList.size(); i++) {
309
                        if(i == 0) {
310
                                try {
311
                                        if(geomList.get(0).getType() == TYPES.POINT || geomList.get(0).getType() == TYPES.MULTIPOINT)
312
                                                newGeom = (MultiPoint)geomManager.create(TYPES.MULTIPOINT, SUBTYPES.GEOM2D);
313
                                        if(geomList.get(0).getType() == TYPES.CURVE || geomList.get(0).getType() == TYPES.MULTICURVE)
314
                                                newGeom = (MultiCurve)geomManager.create(TYPES.MULTICURVE, SUBTYPES.GEOM2D);
315
                                        if(geomList.get(0).getType() == TYPES.SURFACE || geomList.get(0).getType() == TYPES.MULTISURFACE)
316
                                                newGeom = (MultiSurface)geomManager.create(TYPES.MULTISURFACE, SUBTYPES.GEOM2D);
317
                                } catch (CreateGeometryException e) {
318
                                }        
319
                        }
320

    
321
                        if(geomList.get(i) instanceof Surface) {
322
                                ((MultiSurface)newGeom).addPrimitive((Surface)geomList.get(i));
323
                        } 
324
                        if(geomList.get(i) instanceof MultiSurface) {
325
                                int nPrimitives = ((MultiSurface)geomList.get(i)).getPrimitivesNumber();
326
                                for (int iPrimitive = 0; iPrimitive < nPrimitives; iPrimitive++) {
327
                                        ((MultiSurface)newGeom).addPrimitive(((MultiSurface)geomList.get(i)).getSurfaceAt(iPrimitive));
328
                                }
329
                        }
330
                        if(geomList.get(i) instanceof Curve) {
331
                                ((MultiCurve)newGeom).addPrimitive((Curve)geomList.get(i));
332
                        } 
333
                        if(geomList.get(i) instanceof MultiCurve) {
334
                                int nPrimitives = ((MultiSurface)geomList.get(i)).getPrimitivesNumber();
335
                                for (int iPrimitive = 0; iPrimitive < nPrimitives; iPrimitive++) {
336
                                        ((MultiCurve)newGeom).addPrimitive(((MultiCurve)geomList.get(i)).getCurveAt(iPrimitive));
337
                                }
338
                        }
339
                        if(geomList.get(i) instanceof Point) {
340
                                ((MultiPoint)newGeom).addPrimitive((Point)geomList.get(i));
341
                        } 
342
                        if(geomList.get(i) instanceof MultiPoint) {
343
                                int nPrimitives = ((MultiPoint)geomList.get(i)).getPrimitivesNumber();
344
                                for (int iPrimitive = 0; iPrimitive < nPrimitives; iPrimitive++) {
345
                                        ((MultiPoint)newGeom).addPrimitive(((MultiPoint)geomList.get(i)).getPointAt(iPrimitive));
346
                                }
347
                        }
348

    
349
                }
350

    
351
                return newGeom;
352
        }
353
        
354
        /**
355
         * Computes the union of gemetries in the list
356
         * @param listInput
357
         * @return
358
         */
359
        private Geometry computesUnion(List<Geometry> listInput) {
360
                List<com.vividsolutions.jts.geom.Geometry> listResult = new ArrayList<com.vividsolutions.jts.geom.Geometry>();
361
                for (int i = listInput.size() - 1; i >= 0; i--) {
362
                        listResult.add(GeometryUtil.geomToJTS(listInput.get(i)));
363
                        listInput.remove(i);
364
                }
365
                com.vividsolutions.jts.geom.Geometry newGeom = null;
366
                while(listResult.size() > 1) {
367
                        List<com.vividsolutions.jts.geom.Geometry> list = new ArrayList<com.vividsolutions.jts.geom.Geometry>();
368
                        for (int i = 0; i < listResult.size(); i = i + 2) {
369
                                if(i == (listResult.size() - 1))
370
                                        list.add(listResult.get(i));
371
                                else {
372
                                        newGeom = JTSFacade.union(listResult.get(i), listResult.get(i + 1));
373
                                        list.add(newGeom);
374
                                }
375
                        }
376
                        listResult = list;
377
                }
378
                return GeometryUtil.jtsToGeom(newGeom);
379
        }
380

    
381
        private Double updateAny(Double min, Object value) {
382
                if(value instanceof Double)
383
                        return (Double)value;
384
                else if(value instanceof Integer)
385
                        return ((Integer)value).doubleValue();
386
                return min;
387
        }
388
        
389
        private Double updateMinimum(Double min, Object value) {
390
                if(value instanceof Double && ((Double)value).doubleValue() < min)
391
                        return (Double)value;
392
                else if(value instanceof Integer && ((Integer)value).intValue() < min)
393
                        return ((Integer)value).doubleValue();
394
                return min;
395
        }
396
        
397
        private Double updateMaximum(Double max, Object value) {
398
                if(value instanceof Double && ((Double)value).doubleValue() > max)
399
                        return (Double)value;
400
                else if(value instanceof Integer && ((Integer)value).intValue() > max)
401
                        return ((Integer)value).doubleValue();
402
                return max;
403
        }
404
        
405
        private Double sum(Double current, Object value) {
406
                if(value instanceof Double)
407
                        return ((Double)value) + current;
408
                else if(value instanceof Integer)
409
                        return ((Integer)value) + current;
410
                return current;
411
        }
412

    
413
        /**
414
         * Gets the list of grouped values
415
         * @param featureStore
416
         * @param groupByField
417
         * @return
418
         * @throws DataException
419
         */
420
        private Set<String> getGroupedValues(FeatureStore featureStore, String groupByField) throws DataException {
421
                HashMap<String, String> valueGrouped = new HashMap<String, String>();
422
                FeatureSet featureSet = featureStore.getFeatureSet();
423
                DisposableIterator it = featureSet.iterator();
424
                while( it.hasNext() ) {
425
                        Feature feature = (Feature)it.next();
426
                        Object obj = feature.get(groupByField);
427
                        String s = null;
428
                        if(obj instanceof String)
429
                                s = new String(((String)obj));
430
                        else if(obj instanceof Double)
431
                                s = String.valueOf((Double)obj);
432
                        else if(obj instanceof Integer)
433
                                s = String.valueOf((Integer)obj);
434
                        else if(obj instanceof Float)
435
                                s = String.valueOf((Float)obj);
436
                        else if(obj instanceof Boolean)
437
                                s = String.valueOf((Boolean)obj);
438
                        else if(obj instanceof Long)
439
                                s = String.valueOf((Long)obj);
440
                        else if(obj instanceof Byte)
441
                                s = String.valueOf((Byte)obj);
442
                        else if(obj instanceof Date)
443
                                s = ((Date)obj).toString();
444
                        if(valueGrouped.get(s) == null) {
445
                                valueGrouped.put(s, s);
446
                        }
447
                }
448
                it.dispose();
449
                featureSet.dispose();
450
                return valueGrouped.keySet();
451
        }
452
        
453
    /**
454
     * Builds the output FeatureStore
455
     * 
456
     * @param featureType
457
     * @return FeatureStore
458
     */
459
    private FeatureStore buildOutPutStore(FeatureType featureType,
460
                    String sextanteLayerName,
461
                    String groupByField,
462
                    String[] fieldList,
463
                    String[] funcList,
464
                    int geomOption,
465
                    int inputShapeType) {
466
            int len = fieldList != null ? fieldList.length + 2 : 2;
467
            
468
        Class<?>[] types = new Class[len];
469
        attrNames = new String[len];
470

    
471
        FeatureAttributeDescriptor desc = featureType.getAttributeDescriptor(groupByField);
472
        attrNames[0] = desc.getName();
473
        types[0] = desc.getObjectClass();
474
        
475
        if(fieldList != null) {
476
                for (int i = 1; i < attrNames.length - 1; i++) {
477
                        desc = featureType.getAttributeDescriptor(fieldList[i - 1]);
478
                        attrNames[i] = desc.getName();
479
                        if(attrNames[i].length() >= 6)
480
                                attrNames[i] = attrNames[i].substring(0, 5);
481
                        attrNames[i] += "_" + funcList[i - 1];
482
                        types[i] = desc.getObjectClass(); 
483
                }
484
        }
485
        
486
        attrNames[attrNames.length - 1] = featureType.getDefaultGeometryAttributeName();
487
        types[types.length - 1] = featureType.getDefaultGeometryAttribute().getObjectClass();
488
        
489
        try {
490
            IVectorLayer output = getNewVectorLayer(RESULT, sextanteLayerName,
491
                            inputShapeType, types, attrNames);
492
            return ((FlyrVectIVectorLayer) output).getFeatureStore();
493
        } catch (UnsupportedOutputChannelException e) {
494
            Sextante.addErrorToLog(e);
495
        } catch (GeoAlgorithmExecutionException e) {
496
            Sextante.addErrorToLog(e);
497
        }
498
        return null;
499
    }
500
    
501
    /**
502
     * Gets the list of fields index to add to the table. 
503
     * @param fieldsString
504
     * @return
505
     */
506
        private int[] getFieldList(String fieldsString) {
507
                String[] list = fieldsString.split(";");
508
                int[] l = new int[list.length];
509
                for (int i = 0; i < list.length; i++) {
510
                        try {
511
                                l[i] = new Integer(list[i]);
512
                        } catch (NumberFormatException e) {
513
                                return null;
514
                        }
515
                }
516
                return l;
517
        }
518
        
519
    @Override
520
    public Class<? extends GeoAlgorithmParametersPanel> getCustomParametersPanelClass() {
521
        return GroupByParametersPanel.class;
522
    }
523

    
524
}