Statistics
| Revision:

root / org.gvsig.legend.proportionalsymbols.app.mainplugin / trunk / org.gvsig.legend.proportionalsymbols.app.mainplugin / src / main / java / org / gvsig / symbology / fmap / rendering / ProportionalSymbolsLegend.java @ 1855

History | View | Annotate | Download (19 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
package org.gvsig.symbology.fmap.rendering;
42

    
43
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
45

    
46
import org.gvsig.fmap.dal.feature.Feature;
47
import org.gvsig.fmap.geom.Geometry;
48
import org.gvsig.fmap.geom.GeometryLocator;
49
import org.gvsig.fmap.geom.GeometryManager;
50
import org.gvsig.fmap.mapcontext.MapContextLocator;
51
import org.gvsig.fmap.mapcontext.MapContextManager;
52
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
53
import org.gvsig.fmap.mapcontext.rendering.legend.ZSort;
54
import org.gvsig.fmap.mapcontext.rendering.legend.events.IntervalLegendEvent;
55
import org.gvsig.fmap.mapcontext.rendering.legend.events.LabelLegendEvent;
56
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
57
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent;
58
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
59
import org.gvsig.fmap.mapcontext.rendering.legend.events.ValueLegendEvent;
60
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
61
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
62
import org.gvsig.i18n.Messages;
63
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.VectorialUniqueValueLegend;
64
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl.MarkerFillSymbol;
65
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl.MultiLayerFillSymbol;
66
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
67
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
68
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.SimpleMarkerFillPropertiesStyle;
69
import org.gvsig.tools.ToolsLocator;
70
import org.gvsig.tools.dynobject.DynStruct;
71
import org.gvsig.tools.persistence.PersistenceManager;
72
import org.gvsig.tools.persistence.PersistentState;
73
import org.gvsig.tools.persistence.exception.PersistenceException;
74
import org.gvsig.tools.util.Callable;
75

    
76

    
77
/**
78
 * Implements a legend which represents the quantitative information
79
 * (numeric values). This representation is possible thanks to a symbol
80
 * whose size is different each time (depending on the numeric values
81
 * and if we want to use normalization or not).
82
 *
83
 * @author jaume dominguez faus - jaume.dominguez@iver.es
84
 * @author jldominguez
85
 */
86
public class ProportionalSymbolsLegend extends VectorialUniqueValueLegend  {
87

    
88
    private static Logger logger = LoggerFactory.getLogger(ProportionalSymbolsLegend.class);
89
    public static final String
90
    PROPORTIONAL_SYMBOL_LEGEND_NAME =
91
        "PROPORTIONAL_SYMBOL_LEGEND";
92
    public static final String
93
    PROPORTIONAL_SYMBOL_LEGEND_PERSISTENCE_DEFINITION_NAME =
94
        "PROPORTIONAL_SYMBOL_LEGEND_PERSISTENCE_DEFINITION";
95

    
96
        public void setClassifyingFieldNames(String[] fNames) {
97
                super.setClassifyingFieldNames(fNames);
98
                valueField = fNames[0];
99
                normalizationField = fNames[1];
100
        }
101

    
102
        private ISymbol backgroundSymbol;
103
        private String valueField;
104
        private String normalizationField;
105
        private double minSize;
106
        private double maxSize;
107
        private int templateShapeType;
108
        private boolean useNormalization;
109
        private double maxFeature, minFeature;
110
        private ZSort zSort = null;
111

    
112

    
113
        public ISymbol getSymbolByValue(Object key) {
114
                return null;
115
        }
116

    
117
        public ISymbol getSymbolByFeature(Feature feat) {
118

    
119
                ISymbol theSymbol = getDefaultSymbol();
120
                ISymbol auxSymbol;
121

    
122
                double value = 0;
123
                double normValue = 0;
124
                double size;
125
                double separation = maxSize-minSize;
126

    
127
                if (separation == 0) {
128
                        separation = 1;
129
                }
130

    
131
                try {
132

    
133
                        value = feat.getDouble(this.valueField);
134
                        if (useNormalization) {
135

    
136
                            normValue = feat.getDouble(this.normalizationField);
137
                            if (normValue == 0) {
138
                                size = (value >= 0) ?
139
                                    Double.POSITIVE_INFINITY :
140
                                    Double.NEGATIVE_INFINITY;
141
                            } else {
142
                        value = value / normValue;
143
                        size = minSize + (value * separation) ;
144
                            }
145

    
146
                        } else {
147
                                double difFeat = maxFeature - minFeature;
148
                                double step = difFeat/separation;
149
                                size = minSize + ((value - minFeature)/step);
150
                        }
151

    
152
                } catch (Exception e) {
153
                        logger.info("Error while getting value in ProportionalSymbolsLegend.", e);
154
                        return null;
155
                }
156

    
157
                if (size == Double.NaN || size == Double.POSITIVE_INFINITY
158
                    || size == Double.NEGATIVE_INFINITY) {
159

    
160
            // logger.info("The symbol size is NaN or INFINITE.");
161
                        return null;
162
                }
163

    
164
                Geometry defgeom = feat.getDefaultGeometry();
165
                int def_geom_type = defgeom.getGeometryType().getType();
166

    
167
                if (isPolygonal(def_geom_type) && theSymbol instanceof IMarkerSymbol) {
168

    
169
                        MarkerFillSymbol aux = new MarkerFillSymbol();
170
                        ((IMarkerSymbol) theSymbol).setSize(size);
171
                        aux.setMarker((IMarkerSymbol) theSymbol);
172
                        SimpleMarkerFillPropertiesStyle p = new SimpleMarkerFillPropertiesStyle();
173
                        p.setFillStyle(SimpleMarkerFillPropertiesStyle.SINGLE_CENTERED_SYMBOL);
174
                        aux.setMarkerFillProperties(p);
175
                        theSymbol = aux;
176
                }
177
                else if (isLinear(def_geom_type)) {
178

    
179
                        ILineSymbol line = (ILineSymbol) theSymbol;
180
                        line.setLineWidth(size);
181
                        theSymbol = line;
182
                }
183
                else if (isPoint(def_geom_type)) {
184
                        IMarkerSymbol marker = (IMarkerSymbol) theSymbol;
185
                        marker.setSize(size);
186
                        theSymbol = marker;
187
                }
188

    
189
                if (backgroundSymbol != null) {
190
                        MultiLayerFillSymbol multi = new MultiLayerFillSymbol() ;
191
                        multi.addLayer(backgroundSymbol);
192
                        multi.addLayer(theSymbol);
193
                        return multi;
194
                }
195
                auxSymbol = theSymbol;
196

    
197
                return auxSymbol;
198

    
199
        }
200

    
201
    public static boolean isPolygonal(int ty) {
202
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
203
        return geomManager.isSubtype(Geometry.TYPES.MULTISURFACE, ty) || 
204
            geomManager.isSubtype(Geometry.TYPES.SURFACE, ty);
205
    }
206

    
207
    public static boolean isLinear(int ty) {
208
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
209
        return geomManager.isSubtype(Geometry.TYPES.MULTICURVE, ty) || 
210
            geomManager.isSubtype(Geometry.TYPES.CURVE, ty);
211
    }
212
    
213
    public static boolean isPoint(int ty) {
214
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
215
        return geomManager.isSubtype(Geometry.TYPES.MULTIPOINT, ty) || 
216
            geomManager.isSubtype(Geometry.TYPES.POINT, ty);
217
    }
218

    
219
        /**
220
         * Gets the background symbol which only can appear when the shapetype of the layer
221
         * is polygonal
222
         *
223
         * @return ISymbol the symbol for the background
224
         */
225
        public ISymbol getBackgroundSymbol() {return backgroundSymbol;}
226
        /**
227
         * Sets the background symbol which is used only when the shapetype of the layer is polygonal
228
         *
229
         * @param backgroundSymbol the symbol for the background
230
         */
231
        public void setBackgroundSymbol(ISymbol backgroundSymbol) {this.backgroundSymbol = backgroundSymbol;}
232
        /**
233
         * Obtains the classifying field name to be used to calculate the size of the symbol
234
         *
235
         * @return String  the name of the field
236
         * @throws ReadDriverException
237
         */
238
        public String getValueField() {
239
//                try {
240
//                        // TODO:
241
//                        // Por los alias, al guardar un proyecto no podemos
242
//                        // permitir que se guarde con campos que luego
243
//                        // no van a existir.
244
////                        int id = dataSource.getFieldIndexByName(valueField);
245
////                        valueField = dataSource.getFieldName(id);
246
//                } catch (ReadDriverException e) {
247
//                        e.printStackTrace();
248
//                        throw new RuntimeException(e);
249
//                }
250
                return valueField;
251
        }
252
        /**
253
         * Sets the classifying field name to be used to calculate the size of the symbol
254
         *
255
         * @param String  the name of the field
256
         */
257
        public void setValueField(String valueField) {this.valueField = valueField;}
258
        /**
259
         * Obtains the classifying field name to be used to calculate the size of the symbol when the
260
         * user is doing it with a normalization value.
261
         *
262
         * @return String  the name of the field
263
         */
264
        public String getNormalizationField() {
265
                return normalizationField;
266
        }
267
        /**
268
         * Sets the classifying field name to be used to calculate the size of the symbol when the
269
         * user is doing it with a normalization value.
270
         *
271
         * @param String  the name of the field
272
         */
273
        public void setNormalizationField(String normalizationField) {this.normalizationField = normalizationField;}
274
        /**
275
         * Obtains the minimum size for the symbol
276
         *
277
         * @return double  the minimum size for the symbol
278
         */
279
        public double getMinSize() {return minSize;}
280
        /**
281
         * Sets the minimum size for the symbol
282
         *
283
         * @param minSize  the minimum size for the symbol
284
         */
285
        public void setMinSize(double minSize) {this.minSize = minSize;}
286
        /**
287
         * Obtains the maximum size for the symbol
288
         *
289
         * @return double  the minimum size for the symbol
290
         */
291
        public double getMaxSize() {return maxSize;}
292
        /**
293
         * Sets the maximum size for the symbol
294
         *
295
         * @param maxSize  the minimum size for the symbol
296
         */
297
        public void setMaxSize(double maxSize) {this.maxSize = maxSize;}
298
        /**
299
         * Obtains the shapetype of the template symbol
300
         *
301
         * @return int shape type for the template symbol
302
         */
303
        public int getTemplateShapeType() {return templateShapeType;}
304
        /**
305
         * Sets the shapetype of the template symbol
306
         *
307
         * @param templateShapeType shape type for the template symbol
308
         */
309
        public void setTemplateShapeType(int tst) {
310

    
311
                if (isPolygonal(getShapeType())) {
312
                        if (isPoint(tst) || isPolygonal(tst)) {
313
                            this.templateShapeType = tst;
314
                        }
315
                } else {
316

    
317
                    if ((isPoint(tst) && isPoint(getShapeType()))
318
                        || (isLinear(tst) && isLinear(getShapeType()))) {
319
                        // || (getShapeType() == Geometry.TYPES.NULL)) {
320

    
321
                        this.templateShapeType = tst;
322
                    }
323
                }
324
        }
325

    
326
        /**
327
         * Obtains the boolean which is true if the user wants to calculate the size of the
328
         * symbol using a normalization field.
329
         *
330
         * @return boolean true if the user wants normalization.Otherwise, false.
331
         */
332
        public boolean getUseNormalization() {return useNormalization;}
333
        /**
334
         * Sets the boolean which is true if the user wants to calculate the size of the
335
         * symbol using a normalization field.
336
         *
337
         * @param useNormalization true if the user wants normalization.Otherwise, false.
338
         */
339
        public void setUseNormalization(boolean useNormalization) {this.useNormalization = useNormalization;}
340
        /**
341
         * Obtains the variable which represents the maximum value of the classifying field that is used
342
         * to calculate the size of the symbol
343
         *
344
         * @return double  the maximum value of the classifying field
345
         */
346
        public double getMaxFeature() {return maxFeature;}
347
        /**
348
         * Sets the variable which represents the maximum value of the classifying field that is used
349
         * to calculate the size of the symbol
350
         *
351
         * @param maxFeature
352
         */
353
        public void setMaxFeature(double maxFeature) {this.maxFeature = maxFeature;}
354
        /**
355
         * Obtains the variable which represents the minimum value of the classifying field that is used
356
         * to calculate the size of the symbol
357
         *
358
         * @return double  the minimum value of the classifying field
359
         */
360
        public double getMinFeature() {return minFeature;}
361
        /**
362
         * Sets the variable which represents the minimum value of the classifying field that is used
363
         * to calculate the size of the symbol
364
         *
365
         * @param minFeature
366
         */
367
        public void setMinFeature(double minFeature) {this.minFeature = minFeature;}
368

    
369

    
370
        public ISymbol[] getSymbols() {
371
                ISymbol[] auxSymbols=super.getSymbols();
372
                if(backgroundSymbol != null){
373
                        ISymbol[] symbols=new ISymbol[auxSymbols.length+1];
374
                        for (int i = 0; i < auxSymbols.length; i++) {
375
                                symbols[i]=auxSymbols[i];
376
                        }
377
                        symbols[symbols.length-1]=backgroundSymbol;
378
                        return symbols;
379
                } else {
380
                        return auxSymbols;
381
                }
382
        }
383

    
384

    
385

    
386
        public ZSort getZSort() {
387
                if (zSort == null){
388
                        zSort = new MyZSort(this);
389
                }
390
                return zSort;
391
        }
392

    
393
        public void setZSort(ZSort zSort){
394
                return;
395
        }
396

    
397
        private class MyZSort extends ZSort {
398

    
399
                public MyZSort(ILegend legend) {
400
                        super(legend);
401
                }
402

    
403
                public void legendChanged(LegendChangedEvent e) {
404
                }
405

    
406
                public String getClassName() {
407
                        return getClass().getName();
408
                }
409

    
410
                public int getLevelCount() {
411
                        int levels = 0;
412
                        if (backgroundSymbol!=null){
413
                                if(backgroundSymbol instanceof IMultiLayerSymbol){
414
                                        levels += ((IMultiLayerSymbol)backgroundSymbol).getLayerCount();
415
                                } else {
416
                                        levels += 1;
417
                                }
418
                        }
419
                        ISymbol sym = getDefaultSymbol();
420
                        if(getDefaultSymbol() instanceof IMultiLayerSymbol){
421
                                levels += ((IMultiLayerSymbol)sym).getLayerCount();
422
                        } else {
423
                                levels += 1;
424
                        }
425
                        return levels+1;
426
                }
427

    
428

    
429
                public void setUsingZSort(boolean usingZSort) {
430
                }
431

    
432
                public void setLevels(ISymbol sym, int[] values) {
433
                }
434

    
435

    
436
                public void setLevels(int row, int[] values) {
437
                }
438

    
439
                public int[] getLevels(ISymbol sym) {
440
                        return getLevels(0);
441
                }
442

    
443
                public int[] getLevels(int row) {
444
                        int levelsCount = getLevelCount();
445
                        int[] levels = new int[levelsCount];
446
                        int bgLevels = 1;
447
                        if (backgroundSymbol!=null){
448
                                if(backgroundSymbol instanceof IMultiLayerSymbol){
449
                                        bgLevels = ((IMultiLayerSymbol)backgroundSymbol).getLayerCount();
450
                                }
451
                                for (int i=0; i<bgLevels; i++) {
452
                                        levels[i]=i;
453
                                }
454
                        }
455

    
456
                        ISymbol sym = getDefaultSymbol();
457
                        int frLevels = 1;
458
                        if(getDefaultSymbol() instanceof IMultiLayerSymbol){
459
                                frLevels = ((IMultiLayerSymbol)sym).getLayerCount();
460
                        }
461
                        for (int i=0; i<frLevels; i++) {
462
                                levels[i+bgLevels]=i+bgLevels;
463
                        }
464
                        levels[frLevels+bgLevels]=frLevels+bgLevels;
465
                        return levels;
466
                }
467

    
468

    
469
                public boolean isUsingZSort() {
470
                        return backgroundSymbol!=null;
471
                }
472

    
473

    
474
                public ISymbol[] getSymbols() {
475
                        return getSymbols();
476
                }
477

    
478
                public String[] getDescriptions() {
479
                        return getDescriptions();
480
                }
481

    
482
                public int getTopLevelIndexAllowed() {
483
                        return getLevelCount();
484
                }
485

    
486
                @Override
487
                public String toString() {
488
                        String out = "ZSort for ProportionalSymbolLegend";
489
                        return out;
490
                }
491

    
492
                public boolean symbolChanged(SymbolLegendEvent e) {
493
                        return true;
494
                }
495

    
496
                public boolean classifiedSymbolChange(SymbolLegendEvent e) {
497
                        return true;
498
                }
499

    
500
                public boolean intervalChange(IntervalLegendEvent e) {
501
                        return false;
502
                }
503

    
504
                public boolean valueChange(ValueLegendEvent e) {
505
                        return false;
506
                }
507

    
508
                // TODO should not exist here
509
                public boolean labelFieldChange(LabelLegendEvent e) {
510
                        return false;
511
                }
512

    
513
                public void legendCleared(LegendClearEvent event) {
514
                }
515
        }
516

    
517

    
518
    public void loadFromState(PersistentState state)
519
        throws PersistenceException {
520

    
521
        int[] ft = state.getIntArray("fieldTypes");
522
        this.setClassifyingFieldTypes(ft);
523

    
524
        this.valueField = state.getString("valueField");
525
        this.normalizationField = state.getString("normalizationField");
526
        this.templateShapeType = state.getInt("templateShapeType");
527
        this.maxSize = state.getDouble("maxSize");
528
        this.minSize = state.getDouble("minSize");
529
        this.maxFeature = state.getDouble("maxFeature");
530
        this.minFeature = state.getDouble("minFeature");
531
        this.useNormalization = state.getBoolean("useNormalization");
532

    
533
        ISymbol sym = (ISymbol) state.get("defaultSymbol");
534
        this.setDefaultSymbol(sym);
535

    
536
        sym = (ISymbol) state.get("backgroundSymbol");
537
        this.setBackgroundSymbol(sym);
538

    
539
        String[] fieldNames = new String[2];
540
        fieldNames[0]= valueField;
541
        if (normalizationField.compareTo(Messages.getText("none")) == 0) {
542
            fieldNames[1]= fieldNames[0];
543
        } else {
544
            fieldNames[1] = normalizationField;
545
        }
546
        setClassifyingFieldNames(fieldNames);
547
    }
548

    
549

    
550
    public void saveToState(PersistentState state) throws PersistenceException {
551

    
552
        int[] ft = this.getClassifyingFieldTypes();
553
        state.set("fieldTypes", ft);
554

    
555
        state.set("valueField", this.valueField);
556
        state.set("normalizationField", this.normalizationField);
557
        state.set("templateShapeType", this.templateShapeType);
558
        state.set("maxSize", this.maxSize);
559
        state.set("minSize", this.minSize);
560
        state.set("maxFeature", this.maxFeature);
561
        state.set("minFeature", this.minFeature);
562
        state.set("useNormalization", this.useNormalization);
563
        state.set("defaultSymbol", this.getDefaultSymbol());
564
        state.set("backgroundSymbol", this.backgroundSymbol);
565
    }
566

    
567

    
568
    public static class RegisterPersistence implements Callable {
569

    
570
        public Object call() throws Exception {
571

    
572
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
573
            if (manager
574
                .getDefinition(PROPORTIONAL_SYMBOL_LEGEND_PERSISTENCE_DEFINITION_NAME) == null) {
575
                DynStruct definition =
576
                    manager
577
                        .addDefinition(
578
                            ProportionalSymbolsLegend.class,
579
                            PROPORTIONAL_SYMBOL_LEGEND_PERSISTENCE_DEFINITION_NAME,
580
                            PROPORTIONAL_SYMBOL_LEGEND_PERSISTENCE_DEFINITION_NAME
581
                                + " Persistence definition", null, null);
582

    
583
                definition.addDynFieldString("valueField").setMandatory(true);
584
                definition.addDynFieldString("normalizationField").setMandatory(true);
585
                definition.addDynFieldInt("templateShapeType").setMandatory(true);
586
                definition.addDynFieldArray("fieldTypes").setClassOfItems(Integer.class).setMandatory(true);
587
                definition.addDynFieldDouble("maxSize").setMandatory(true);
588
                definition.addDynFieldDouble("minSize").setMandatory(true);
589
                definition.addDynFieldDouble("maxFeature").setMandatory(true);
590
                definition.addDynFieldDouble("minFeature").setMandatory(true);
591
                definition.addDynFieldBoolean("useNormalization").setMandatory(true);
592

    
593
                definition.addDynFieldObject("defaultSymbol")
594
                .setClassOfValue(ISymbol.class).setMandatory(true);
595
                definition.addDynFieldObject("backgroundSymbol")
596
                .setClassOfValue(ISymbol.class).setMandatory(true);
597
            }
598
            return Boolean.TRUE;
599
        }
600

    
601
    }
602

    
603
    public static class RegisterLegend implements Callable {
604

    
605
        public Object call() throws Exception {
606
            MapContextManager manager =
607
                MapContextLocator.getMapContextManager();
608

    
609
            manager.registerLegend(
610
                PROPORTIONAL_SYMBOL_LEGEND_NAME,
611
                ProportionalSymbolsLegend.class);
612

    
613
            return Boolean.TRUE;
614
        }
615

    
616
    }
617

    
618
}