Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / rendering / legend / AbstractIntervalLegend.java @ 28092

History | View | Annotate | Download (16.6 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
*
44
* $Id: AbstractIntervalLegend.java 21144 2008-06-03 15:47:31Z vcaballero $
45
* $Log$
46
* Revision 1.12  2007-09-19 16:25:39  jaume
47
* ReadExpansionFileException removed from this context and removed unnecessary imports
48
*
49
* Revision 1.11  2007/09/10 15:47:11  jaume
50
* *** empty log message ***
51
*
52
* Revision 1.10  2007/08/03 09:22:08  jaume
53
* refactored class names
54
*
55
* Revision 1.9  2007/08/02 10:19:03  jvidal
56
* implements IPersistance
57
*
58
* Revision 1.8  2007/08/01 11:45:59  jaume
59
* passing general tests (drawing test yet missing)
60
*
61
* Revision 1.7  2007/05/28 15:36:42  jaume
62
* *** empty log message ***
63
*
64
* Revision 1.6  2007/05/17 09:32:06  jaume
65
* *** empty log message ***
66
*
67
* Revision 1.5  2007/05/10 14:13:36  jaume
68
* *** empty log message ***
69
*
70
* Revision 1.4  2007/05/10 09:44:08  jaume
71
* Refactored legend interface names
72
*
73
* Revision 1.3  2007/03/27 09:28:40  jaume
74
* *** empty log message ***
75
*
76
* Revision 1.2  2007/03/09 11:20:56  jaume
77
* Advanced symbology (start committing)
78
*
79
* Revision 1.1.2.2  2007/02/15 16:23:44  jaume
80
* *** empty log message ***
81
*
82
* Revision 1.1.2.1  2007/02/13 16:19:19  jaume
83
* graduated symbol legends (start commiting)
84
*
85
*
86
*/
87
package org.gvsig.fmap.mapcontext.rendering.legend;
88

    
89
import java.util.ArrayList;
90
import java.util.Comparator;
91
import java.util.Date;
92
import java.util.Iterator;
93
import java.util.TreeMap;
94

    
95
import org.gvsig.fmap.dal.exception.DataException;
96
import org.gvsig.fmap.dal.feature.DisposableIterator;
97
import org.gvsig.fmap.dal.feature.Feature;
98
import org.gvsig.fmap.dal.feature.FeatureQuery;
99
import org.gvsig.fmap.dal.feature.FeatureReference;
100
import org.gvsig.fmap.dal.feature.FeatureSet;
101
import org.gvsig.fmap.dal.feature.FeatureStore;
102
import org.gvsig.fmap.mapcontext.Messages;
103
import org.gvsig.fmap.mapcontext.exceptions.LegendLayerException;
104
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
105
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbologyFactory;
106
import org.slf4j.Logger;
107
import org.slf4j.LoggerFactory;
108

    
109

    
110
public abstract class AbstractIntervalLegend extends AbstractClassifiedVectorLegend implements IVectorialIntervalLegend{
111
        protected int shapeType;
112

    
113
        public static final int EQUAL_INTERVALS = 0;
114
        public static final int NATURAL_INTERVALS = 1;
115
        public static final int QUANTILE_INTERVALS = 2;
116
        protected TreeMap symbols = new TreeMap //<Object, ISymbol>
117
                        (new Comparator() { //<Object>
118
                public int compare(Object o1, Object o2) {
119
                        if ((o1 != null) && (o2 != null)) {
120
                                if (o1 instanceof NullIntervalValue &&
121
                                                o2 instanceof NullIntervalValue) {
122
                                        return 0;
123
                                }
124

    
125
                                if (o2 instanceof NullIntervalValue) {
126
                                        return 1;
127
                                }
128

    
129
                                if (o1 instanceof NullIntervalValue) {
130
                                        return -1;
131
                                }
132

    
133
                                FInterval i2 = (FInterval) o2;
134
                                FInterval i1 = (FInterval) o1;
135

    
136
                                if (i1.getMin() > i2.getMin()) {
137
                                        return 1;
138
                                }
139

    
140
                                if (i1.getMin() < i2.getMin()) {
141
                                        return -1;
142
                                }
143
                                if (i1.getMax() < i2.getMax()) {
144
                                        return -1;
145
                                }
146
                                if (i1.getMax() > i2.getMax()) {
147
                                        return 1;
148
                                }
149
                        }
150

    
151
                        return 0;
152
                }
153
        });
154
        protected ArrayList keys = new ArrayList(); //<Object>
155
        protected int index = 0;
156
        protected String[] fieldNames;
157
//        protected int fieldId;
158
        protected ISymbol defaultSymbol;
159
        protected FeatureStore featureStore;
160
        protected int intervalType = NATURAL_INTERVALS;
161
        protected boolean useDefaultSymbol = false;
162

    
163
        final static private Logger logger = LoggerFactory.getLogger(AbstractIntervalLegend.class);
164
        public void addSymbol(Object key, ISymbol symbol) {
165
                symbols.put(key, symbol);
166
                keys.add(key);
167
                fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(null, symbol));
168
        }
169

    
170
        /*
171
         * @see com.iver.cit.gvsig.fmap.rendering.IVectorialLegend#getSymbol(int)
172
         */
173
        public ISymbol getSymbol(FeatureReference featureID) throws DataException {
174
                Object val = featureStore.getFeatureByReference(featureID).get(getClassifyingFieldNames()[0]);
175
                IInterval interval = getInterval(val);
176
                ISymbol theSymbol = getSymbolByInterval(interval);
177

    
178

    
179
                if (theSymbol != null) {
180
                        return theSymbol;
181
                } else if (useDefaultSymbol) {
182
                        return getDefaultSymbol();
183
                }
184

    
185
                return null;
186
        }
187

    
188
        public ISymbol getSymbolByFeature(Feature feat) {
189
                Object val = feat.get(getClassifyingFieldNames()[0]);
190
                IInterval interval = getInterval(val);
191
                ISymbol theSymbol = getSymbolByInterval(interval);
192

    
193
                return theSymbol;
194
        }
195

    
196

    
197
        public FInterval[] calculateIntervals(FeatureStore featureStore, String fieldName, int numIntervalos, int shapeType)
198
        throws LegendLayerException, DataException {
199
                logger.debug("elRs.start()");
200
//                recordSet.start();
201

    
202
//                int idField = -1;
203
                FeatureSet set = null;
204
                DisposableIterator iterator = null;
205
                try {
206

    
207
                setClassifyingFieldNames(new String[] {fieldName});
208

    
209
                String[] fieldNames = getClassifyingFieldNames();
210
                FeatureQuery featureQuery=featureStore.createFeatureQuery();
211
                featureQuery.setAttributeNames(fieldNames);
212
                set = featureStore.getFeatureSet(featureQuery);
213
                        iterator = set.fastIterator();
214

    
215

    
216
//                for (int i = 0; i < recordSet.getFieldCount(); i++) {
217
//                        String nomAux = recordSet.getFieldName(i).trim();
218
//
219
//                        if (fieldNames[0].compareToIgnoreCase(nomAux) == 0) {
220
//                                idField = i;
221
//
222
//                                break;
223
//                        }
224
//                }
225

    
226
//                if (idField == -1) {
227
//                        logger.error("Campo no reconocido " + fieldNames);
228
//
229
//                        return null;
230
//                }
231

    
232
                double minValue = Double.MAX_VALUE;
233
                double maxValue = Double.NEGATIVE_INFINITY;
234

    
235
                VectorialIntervalLegend auxLegend = LegendFactory.
236
                    createVectorialIntervalLegend(shapeType);
237

    
238
                Object clave;
239

    
240
                while (iterator.hasNext()) {
241
                        Feature feature = (Feature) iterator.next();
242

    
243
//                for (int j = 0; j < recordSet.getRowCount(); j++) {
244
                        clave = feature.get(fieldName);
245

    
246
                        IInterval interval = auxLegend.getInterval(clave);
247

    
248
                        ////Comprobar que no esta repetido y no hace falta introducir en el hashtable el campo junto con el simbolo.
249
                        if (auxLegend.getSymbolByInterval(interval) == null) {
250
                                //si no esta creado el simbolo se crea
251
                                double valor = 0;
252

    
253

    
254
                                if (clave instanceof Number) {
255
                                        valor=((Number)clave).doubleValue();
256
                                }else if (clave instanceof Date) {
257
                                        //TODO POR IMPLEMENTAR
258
                                        ///valorDate = elRs.getFieldValueAsDate(idField);
259
                                        ///if (valorDate.before(minValueDate)) minValueDate = valorDate;
260
                                        ///if (valorDate.after(maxValueDate)) maxValueDate = valorDate;
261
                                } else if (clave instanceof NullValue) {
262
                                        continue;
263
                                }
264

    
265
                                if (valor < minValue) {
266
                                        minValue = valor;
267
                                }
268

    
269
                                if (valor > maxValue) {
270
                                        maxValue = valor;
271
                                }
272
                        }
273
                }
274

    
275
                FInterval[] intervalArray = null;
276
                switch (getIntervalType()) {
277
                case VectorialIntervalLegend.EQUAL_INTERVALS:
278
                        intervalArray = calculateEqualIntervals(numIntervalos,
279
                                        minValue, maxValue, fieldName);
280

    
281
                        break;
282

    
283
                case VectorialIntervalLegend.NATURAL_INTERVALS:
284
                        intervalArray = calculateNaturalIntervals(featureStore, numIntervalos,
285
                                        minValue, maxValue, fieldName);
286

    
287
                        break;
288

    
289
                case VectorialIntervalLegend.QUANTILE_INTERVALS:
290
                        intervalArray = calculateQuantileIntervals(featureStore, numIntervalos,
291
                                        minValue, maxValue, fieldName);
292

    
293
                        break;
294
                }
295
//                recordSet.stop();
296
                return intervalArray;
297
                } finally {
298
                        if (iterator != null) {
299
                                iterator.dispose();
300
                        }
301
                        if (set != null) {
302
                                set.dispose();
303
                        }
304
                }
305
        }
306

    
307

    
308
    /**
309
     * EQUAL INTERVAL Devuelve un Array con el n?mero de intervalos que se
310
     * quieren crear. Los intervalos se crean con un tama?o igual entre ellos.
311
     * @param numIntervals n?mero de intervalos
312
     * @param minValue Valor m?nimo.
313
     * @param maxValue Valor m?ximo.
314
     * @param fieldName Nombre del campo
315
     *
316
     * @return Array con los intervalos.
317
     */
318
    private FInterval[] calculateEqualIntervals(int numIntervals, double minValue,
319
        double maxValue, String fieldName) {
320
        FInterval[] theIntervalArray = new FInterval[numIntervals];
321
        double step = (maxValue - minValue) / numIntervals;
322

    
323
        if (numIntervals > 1) {
324
            theIntervalArray[0] = new FInterval(minValue, minValue + step);
325

    
326
            for (int i = 1; i < (numIntervals - 1); i++) {
327
                theIntervalArray[i] = new FInterval(minValue + (i * step) +
328
                        0.01, minValue + ((i + 1) * step));
329
            }
330

    
331
            theIntervalArray[numIntervals - 1] = new FInterval(minValue +
332
                    ((numIntervals - 1) * step) + 0.01, maxValue);
333
        } else {
334
            theIntervalArray[0] = new FInterval(minValue, maxValue);
335
        }
336

    
337
        return theIntervalArray;
338
    }
339

    
340
    /**
341
     * NATURAL INTERVAL Devuelve un Array con el n?mero de intervalos que se
342
     * quieren crear. Los intervalos se distribuyen de forma natural.
343
     *
344
     * @param numIntervals n?mero de intervalos
345
     * @param minValue Valor m?nimo.
346
     * @param maxValue Valor m?ximo.
347
     * @param fieldName Nombre del campo
348
     *
349
     * @return Array con los intervalos.
350
     * @throws LegendLayerException
351
     */
352
    private FInterval[] calculateNaturalIntervals(FeatureStore featureStore, int numIntervals, double minValue,
353
        double maxValue, String fieldName) throws LegendLayerException {
354
        NaturalIntervalGenerator intervalGenerator = new NaturalIntervalGenerator(
355
                        featureStore, fieldName, numIntervals);
356

    
357
        try {
358
            intervalGenerator.generarIntervalos();
359
        } catch (DataException e) {
360
                throw new LegendLayerException(Messages.getString("failed_calculating_intervals"), e);
361
        }
362

    
363
        int numIntervalsGen = intervalGenerator.getNumIntervals() - 1;
364

    
365
        if (numIntervalsGen == -1) {
366
            //TODO cuando no puede calcular los intervalos.
367
            numIntervalsGen = 1;
368
        }
369

    
370
        FInterval[] theIntervalArray = new FInterval[numIntervalsGen];
371

    
372
        if (numIntervalsGen > 1) {
373
            theIntervalArray[0] = new FInterval(minValue,
374
                    intervalGenerator.getValorRuptura(0));
375

    
376
            for (int i = 1; i < (numIntervalsGen - 1); i++) {
377
                theIntervalArray[i] = new FInterval(intervalGenerator.getValInit(i -
378
                            1), intervalGenerator.getValorRuptura(i));
379
            }
380

    
381
            theIntervalArray[numIntervalsGen - 1] = new FInterval(intervalGenerator.getValInit(numIntervalsGen -
382
                        2), maxValue);
383
        } else {
384
            theIntervalArray[numIntervalsGen - 1] = new FInterval(minValue,
385
                    maxValue);
386
        }
387

    
388
        return theIntervalArray;
389
    }
390

    
391
    /**
392
     * QUANTILE INTERVAL Devuelve un Array con el n?mero de intervalos que se
393
     * quieren crear. Los intervalos se distribuyen de forma quantile.
394
     * @param recordSet
395
     *
396
     * @param numIntervals n?mero de intervalos
397
     * @param minValue Valor m?nimo.
398
     * @param maxValue Valor m?ximo.
399
     * @param fieldName Nombre del campo
400
     *
401
     * @return Array con los intervalos.
402
     * @throws LegendLayerException
403
     */
404
    private FInterval[] calculateQuantileIntervals(FeatureStore featureStore, int numIntervals, double minValue,
405
        double maxValue, String fieldName) throws LegendLayerException {
406
        QuantileIntervalGenerator intervalGenerator = new QuantileIntervalGenerator(
407
                        featureStore, fieldName, numIntervals);
408

    
409
        try {
410
            intervalGenerator.generarIntervalos();
411
        } catch (DataException e) {
412
                throw new LegendLayerException(Messages.getString("failed_calculating_intervals"), e);
413
        }
414

    
415
        int numIntervalsGen = intervalGenerator.getNumIntervalGen();
416
        FInterval[] theIntervalArray = new FInterval[numIntervalsGen];
417

    
418
        if (intervalGenerator.getNumIntervalGen() > 1) {
419
            theIntervalArray[0] = new FInterval(minValue,
420
                    intervalGenerator.getValRuptura(0));
421

    
422
            for (int i = 1; i < (numIntervalsGen - 1); i++) {
423
                theIntervalArray[i] = new FInterval(intervalGenerator.getValInit(i -
424
                            1), intervalGenerator.getValRuptura(i));
425
            }
426

    
427
            theIntervalArray[numIntervalsGen - 1] = new FInterval(intervalGenerator.getValInit(numIntervalsGen -
428
                        2), maxValue);
429
        } else {
430
            theIntervalArray[numIntervalsGen - 1] = new FInterval(minValue,
431
                    maxValue);
432
        }
433

    
434
        return theIntervalArray;
435
    }
436

    
437
    public ISymbol getSymbolByInterval(IInterval key) {
438

    
439
                if (key == null){
440
                        if (isUseDefaultSymbol()) {
441
                                return defaultSymbol;
442
                        }
443
                        return null;
444
                }
445
                if (symbols.containsKey(key)) {
446
                        return (ISymbol) symbols.get(key);
447
                }
448

    
449
                if (isUseDefaultSymbol()) {
450
                        return defaultSymbol;
451
                }
452

    
453
                return null;
454
        }
455

    
456

    
457
        public String[] getDescriptions() {
458
                String[] descriptions = new String[symbols.size()];
459
                ISymbol[] auxSym = getSymbols();
460

    
461
                for (int i = 0; i < descriptions.length; i++) {
462
                        descriptions[i] = auxSym[i].getDescription();
463
                }
464

    
465
                return descriptions;
466
        }
467

    
468

    
469
        public Object[] getValues() {
470
                return symbols.keySet().toArray();
471
        }
472

    
473
        public void clear() {
474
                index = 0;
475
                keys.clear();
476
                symbols.clear();
477
        }
478

    
479
        public ISymbol[] getSymbols() {
480
                return (ISymbol[]) symbols.values().toArray(new ISymbol[0]);
481
        }
482

    
483
        public String[] getClassifyingFieldNames() {
484
                return fieldNames;
485
        }
486

    
487
        public void setDefaultSymbol(ISymbol s) {
488
            ISymbol old = defaultSymbol;
489
                if (s == null) {
490
                        throw new NullPointerException("Default symbol cannot be null");
491
                }
492
                defaultSymbol = s;
493
                fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, defaultSymbol));
494
        }
495

    
496
        public void setClassifyingFieldNames(String[] fieldNames) {
497
                this.fieldNames = fieldNames;
498
        }
499

    
500
        public ISymbol getDefaultSymbol() {
501
                NullIntervalValue niv=new NullIntervalValue();
502
                if (symbols.containsKey(niv)) {
503
                        return (ISymbol)symbols.get(niv);
504
                }
505

    
506
                if(defaultSymbol==null) {
507
                        defaultSymbol=SymbologyFactory.createDefaultSymbolByShapeType(shapeType);
508
                }
509
                return defaultSymbol;
510
        }
511

    
512

    
513

    
514
    public void setFeatureStore(FeatureStore featureStore)
515
        throws DataException {
516
                    /*
517
                     * when we move definitely to feature iterators this
518
                     * method
519
                     */
520
                    this.featureStore = featureStore;
521
//                    fieldId = ((FeatureType)featureStore.getFeatureTypes().get(0)).getIndex(fieldNames[0]);
522
    }
523

    
524

    
525
        public IInterval getInterval(Object v) {
526
                for (int i = 0; i < keys.size(); i++) {
527
                        if (((IInterval) keys.get(i)).isInInterval(v)) {
528
                                return (IInterval) keys.get(i);
529
                        }
530
                }
531

    
532
                return null;
533
        }
534

    
535
        public void setIntervalType(int intervalType) {
536
                this.intervalType = intervalType;
537
        }
538

    
539

    
540
        public int getIntervalType() {
541
                return intervalType;
542
        }
543

    
544
        public void useDefaultSymbol(boolean b) {
545
                useDefaultSymbol = b;
546
        }
547

    
548

    
549
        public boolean isUseDefaultSymbol() {
550
                return useDefaultSymbol;
551
        }
552

    
553

    
554
        public void delSymbol(Object obj) {
555
                keys.remove(obj);
556
                symbols.remove(obj);
557
                fireClassifiedSymbolChangeEvent(
558
                                new SymbolLegendEvent(
559
                                                (ISymbol)symbols.remove(obj),
560
                                                null));
561
        }
562

    
563

    
564
        public void replace(ISymbol oldSymbol, ISymbol newSymbol) {
565
                if (symbols.containsValue(oldSymbol)) {
566
                        Iterator it = symbols.keySet().iterator();
567
                        while (it.hasNext()) {
568
                                Object key = it.next();
569
                                if (symbols.get(key).equals(oldSymbol)) {
570
                                        symbols.remove(key);
571
                                        symbols.put(key, newSymbol);
572
                                        fireClassifiedSymbolChangeEvent(
573
                                                        new SymbolLegendEvent(oldSymbol, newSymbol));
574
                                }
575
                        }
576
                }
577
        }
578
}