Statistics
| Revision:

root / org.gvsig.legend.picturemarkersymboltable / trunk / org.gvsig.legend.picturemarkersymboltable / org.gvsig.legend.picturemarkersymboltable.lib / org.gvsig.legend.picturemarkersymboltable.lib.impl / src / main / java / org / gvsig / legend / picturemarkersymboltable / lib / impl / DefaultPictureMarkerSymbolTableLegend.java @ 9512

History | View | Annotate | Download (18.6 KB)

1
package org.gvsig.legend.picturemarkersymboltable.lib.impl;
2

    
3
import java.awt.Color;
4
import java.awt.geom.Point2D;
5
import java.awt.image.BufferedImage;
6
import java.net.URL;
7
import java.util.ArrayList;
8
import java.util.List;
9
import javax.annotation.processing.SupportedSourceVersion;
10
import javax.lang.model.SourceVersion;
11
import org.apache.commons.collections4.map.LRUMap;
12
import org.apache.commons.lang3.StringUtils;
13
import org.gvsig.expressionevaluator.ExpressionBuilder;
14
import org.gvsig.expressionevaluator.ExpressionUtils;
15
import org.gvsig.fmap.dal.DALLocator;
16
import org.gvsig.fmap.dal.DataTypes;
17
import org.gvsig.fmap.dal.StoresRepository;
18
import org.gvsig.fmap.dal.exception.DataException;
19
import org.gvsig.fmap.dal.feature.Feature;
20
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
21
import org.gvsig.fmap.dal.feature.FeatureStore;
22
import org.gvsig.fmap.dal.feature.FeatureType;
23
import org.gvsig.fmap.geom.Geometry;
24
import org.gvsig.fmap.geom.GeometryUtils;
25
import org.gvsig.fmap.mapcontext.MapContextException;
26
import org.gvsig.fmap.mapcontext.rendering.legend.ZSort;
27
import org.gvsig.fmap.mapcontext.rendering.legend.events.IntervalLegendEvent;
28
import org.gvsig.fmap.mapcontext.rendering.legend.events.LabelLegendEvent;
29
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
30
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent;
31
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
32
import org.gvsig.fmap.mapcontext.rendering.legend.events.ValueLegendEvent;
33
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
34
import org.gvsig.legend.picturemarkersymboltable.lib.api.PictureMarkerSymbolTableLegend;
35
import org.gvsig.symbology.SymbologyLocator;
36
import org.gvsig.symbology.SymbologyManager;
37
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractVectorialLegend;
38
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.ISimpleMarkerSymbol;
39
import org.gvsig.tools.ToolsLocator;
40
import org.gvsig.tools.dataTypes.Coercion;
41
import org.gvsig.tools.persistence.PersistentState;
42
import org.gvsig.tools.persistence.exception.PersistenceException;
43
import org.gvsig.tools.swing.api.SimpleImage;
44
import org.gvsig.tools.swing.api.ToolsSwingLocator;
45
import org.slf4j.Logger;
46
import org.slf4j.LoggerFactory;
47

    
48
@SupportedSourceVersion(SourceVersion.RELEASE_8)
49
@SuppressWarnings("UseSpecificCatch")
50
public class DefaultPictureMarkerSymbolTableLegend 
51
        extends AbstractVectorialLegend 
52
        implements PictureMarkerSymbolTableLegend 
53
{
54
    
55
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPictureMarkerSymbolTableLegend.class);
56

    
57
    private static final int IMAGESCACHE_SIZE = 100;
58
    
59
    /** 
60
     * defaultSimbol no se usa para nada. 
61
     * Lo inicializamos en el constructor a SimpleMarkerSymbol por si a caso 
62
     * alguien lo consulta, por ejemplo al persistir el ImageMarkerSimbol.
63
     */
64
    transient private final ISimpleMarkerSymbol defaultSymbol;
65
    
66
    transient private final Coercion toColor;
67
    transient private FeatureStore imagesStore;
68
    transient private ExpressionBuilder expressionBuilder;
69
    transient private final LRUMap<Object, BufferedImage[]> imagesCache;
70
    
71
    private double size;
72
    private int units;
73
    private Color lineToOffsetColor;
74
    private boolean drawLineToOffset;
75

    
76
    private String classifyingFieldName;
77
    private String offsetXFieldName;
78
    private String offsetYFieldName;
79
    private String rotationFieldName;
80
    private String lineToOffsetColorFieldlName;
81

    
82
    private String imagesTableName;
83
    private String imagesTableClassifyingFieldName;
84
    private String imageFieldName;
85
    private String imageSelectedFieldName;
86
    private SimpleImage imageNotFound;
87
    
88
    private double scale;
89
    private boolean reverseDirectionOfAngle;
90

    
91
    private class MyZSort extends ZSort {
92
        
93
        public MyZSort() {
94
                super();
95
        }
96

    
97
        @Override
98
        public void legendChanged(LegendChangedEvent e) throws MapContextException {
99
//                symbols.clear();
100
//                usingZSort = false;
101
//                initialize(e.getNewLegend());
102

    
103
        }
104

    
105
        @Override
106
        public String getClassName() {
107
                return getClass().getName();
108
        }
109

    
110
        @Override
111
        public int getLevelCount() {
112
                return 2;
113
        }
114

    
115
        @Override
116
        public void setUsingZSort(boolean usingZSort) {
117
        }
118

    
119
        @Override
120
        public void setLevels(ISymbol sym, int[] values) {
121
        }
122

    
123
        @Override
124
        public void setLevels(int row, int[] values) {
125
        }
126

    
127
        @Override
128
        public int[] getLevels(ISymbol sym) {
129
                return new int[]{0,1};
130
        }
131

    
132
        @Override
133
        public int[] getLevels(int row) {
134
                return null;
135
        }
136

    
137
        @Override
138
        public boolean isUsingZSort() {
139
                return true;
140
        }
141

    
142
        @Override
143
        public ISymbol[] getSymbols() {
144
                return null;
145
        }
146

    
147
        @Override
148
        public String[] getDescriptions() {
149
            return new String[] {"line", "Image"};
150
        }
151

    
152
        @Override
153
        public int getTopLevelIndexAllowed() {
154
                return 0;
155
        }
156

    
157
        @Override
158
        public String toString() {
159
            return "Line, Image";
160
        }
161

    
162
        @Override
163
        public boolean symbolChanged(SymbolLegendEvent e) {
164
                return true;
165
        }
166

    
167
        @Override
168
        public boolean classifiedSymbolChange(SymbolLegendEvent e) {
169
                return true;
170
        }
171

    
172
        @Override
173
        public boolean intervalChange(IntervalLegendEvent e) {
174
                return false;
175
        }
176

    
177
        @Override
178
        public boolean valueChange(ValueLegendEvent e) {
179
                return false;
180
        }
181

    
182
        // TODO should not exist here
183
        @Override
184
        public boolean labelFieldChange(LabelLegendEvent e) {
185
                return false;
186
        }
187

    
188
        @Override
189
        public void legendCleared(LegendClearEvent event) {
190
        }
191
        
192
    }
193
    
194
    public DefaultPictureMarkerSymbolTableLegend() {
195
        
196
        SymbologyManager symbologyManager = SymbologyLocator.getSymbologyManager();
197
        this.scale = 1;
198
        this.defaultSymbol = symbologyManager.createSimpleMarkerSymbol();
199
        this.toColor = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.COLOR);
200
        this.size = DEFAULT_IMAGE_SIZE;
201
        this.drawLineToOffset = true;
202
        this.lineToOffsetColor = Color.DARK_GRAY;
203
        this.imagesCache = new LRUMap<>(IMAGESCACHE_SIZE);
204
        this.reverseDirectionOfAngle = false;
205
        this.setZSort(new MyZSort());
206
    }
207

    
208
    @Override
209
    public ISymbol getDefaultSymbol() {
210
        return this.defaultSymbol;
211
    }
212

    
213
    @Override
214
    public void setDefaultSymbol(ISymbol is) {
215
        //DO NOTHING
216
    }
217

    
218
    private Color getColor(Feature feature, String attrname, Color defaultValue) {
219
        if( StringUtils.isBlank(attrname) ) {
220
            return defaultValue;
221
        }
222
        try {
223
            return (Color) toColor.coerce(feature.get(attrname));
224
        } catch(Exception ex) {
225
            return defaultValue;
226
        }
227
    }
228
    
229
    @Override
230
    public ISymbol getSymbolByFeature(Feature feature) throws MapContextException {
231
        ImageMarkerSymbol symbol = new ImageMarkerSymbol();
232
        
233
        Point2D.Double offset = new Point2D.Double(0,0);
234
        if( StringUtils.isNotBlank(this.offsetXFieldName)) {
235
            offset.x = feature.getDouble(this.offsetXFieldName)*this.scale;
236
        }
237
        if( StringUtils.isNotBlank(this.offsetYFieldName)) {
238
            offset.y = feature.getDouble(this.offsetYFieldName)*this.scale;
239
        }
240
        symbol.setOffset(offset);
241
        
242
        if( StringUtils.isNotBlank(this.rotationFieldName)) {
243
            if( this.isReverseDirectionOfAngle() ) {
244
                symbol.setRotation(360 - feature.getDouble(this.rotationFieldName));            
245
            } else {
246
                symbol.setRotation(feature.getDouble(this.rotationFieldName));
247
            }
248
        } else {
249
            symbol.setRotation(0);
250
        }
251
        
252
        if( drawLineToOffset && (offset.x!=0 || offset.y!=0))    {
253
            symbol.setDrawLineToOffset(true);
254
            symbol.setLineToOffsetColor(
255
                    getColor(
256
                            feature, 
257
                            this.lineToOffsetColorFieldlName, 
258
                            this.lineToOffsetColor
259
                    )
260
            );
261
        } else {
262
            symbol.setDrawLineToOffset(false);
263
            symbol.setLineToOffsetColor(Color.DARK_GRAY);
264
        }
265
        symbol.setSize(this.size*this.scale);
266
        symbol.setUnit(this.units);
267
        
268
        Object classifyingValue = feature.get(this.classifyingFieldName);
269
        BufferedImage[] images = this.getImages(classifyingValue);
270
        symbol.setImage(images[0]);
271
        symbol.setImageSel(images[1]);
272
        return symbol;
273
    }
274

    
275
    @Override
276
    public int getShapeType() {
277
        return Geometry.TYPES.POINT;
278
    }
279

    
280
    private BufferedImage[] getImages(Object classifyingValue) {
281
        
282
        BufferedImage[] images;
283
        images = this.imagesCache.get(classifyingValue);
284
        if( images!=null ) {
285
            return images;
286
        }
287
        
288
        images = new BufferedImage[] { null, null };        
289
        try {
290
            FeatureStore store = this.getImagesStore();
291
            FeatureType featureType = store.getDefaultFeatureTypeQuietly();
292
            FeatureAttributeDescriptor attr = featureType.getAttributeDescriptor(this.imagesTableClassifyingFieldName);
293
            Object value = attr.coerce(classifyingValue);
294
            ExpressionBuilder builder = this.getExpressionBuilder();
295
            String filter = builder.eq(
296
                    builder.column(this.imagesTableClassifyingFieldName),
297
                    builder.constant(value)
298
            ).toString();
299
            Feature f = store.findFirst(filter);
300
            if( f==null ) {
301
                SimpleImage image = getImageNotFound();
302
                images[0] = image.getBufferedImage();
303
                images[1] = images[0];
304
            } else {
305
                SimpleImage image = (SimpleImage) f.getFromProfile(this.imageFieldName);
306
                if( image != null ) {
307
                    images[0] = image.getBufferedImage();
308
                    images[1] = images[0];
309
                }
310
                image = (SimpleImage) f.getFromProfile(this.imageSelectedFieldName);
311
                if( image != null && !image.isEmpty() ) {
312
                    images[1] = image.getBufferedImage();
313
                }
314
            }
315
        } catch(Exception ex) {
316
            LOGGER.debug("Can't retrieve images from table '"+this.imagesTableName+"'", ex);
317
        }
318
        this.imagesCache.put(classifyingValue, images);
319
        return images;
320
    }
321
    
322
    private SimpleImage getImageNotFound() {
323
        if(this.imageNotFound == null){
324
            URL url = this.getClass().getResource("/images/picturemarkersymboltablelegend/image-not-found.png");
325
            this.imageNotFound = ToolsSwingLocator.getToolsSwingManager().createSimpleImage(url);
326
        }
327
        return this.imageNotFound;
328
    }
329
    
330
    private ExpressionBuilder getExpressionBuilder() {
331
        if( this.expressionBuilder == null ) {
332
            this.expressionBuilder = ExpressionUtils.createExpressionBuilder();
333
        }
334
        return this.expressionBuilder;
335
    }
336
    
337
    private FeatureStore getImagesStore() {
338
        if( this.imagesStore == null ) {
339
            StoresRepository repository = DALLocator.getDataManager().getStoresRepository();
340
            this.imagesStore = (FeatureStore) repository.getStore(this.imagesTableName);
341
        }
342
        return this.imagesStore;
343
    }
344
    
345
    @Override
346
    public void setShapeType(int i) {
347
    }
348

    
349
    @Override
350
    public boolean isUseDefaultSymbol() {
351
        return true;
352
    }
353

    
354
    @Override
355
    public void useDefaultSymbol(boolean bln) {
356
    }
357

    
358
    @Override
359
    public boolean isSuitableForShapeType(int shapeType) {
360
        return GeometryUtils.isSubtype(Geometry.TYPES.POINT, shapeType);
361
    }
362

    
363
    @Override
364
    public void loadFromState(PersistentState state) throws PersistenceException {
365
        super.loadFromState(state);
366
        
367
        this.scale = state.getDouble("scale",1.0);
368
        this.size = state.getDouble("size",DEFAULT_IMAGE_SIZE);
369
        this.units = state.getInt("units",-1);
370
        this.lineToOffsetColor = (Color) state.get("lineToOffsetColor");
371
        this.drawLineToOffset = state.getBoolean("drawLineToOffset",true);
372
        this.reverseDirectionOfAngle = state.getBoolean("reverseDirectionOfAngle",false);
373
        this.classifyingFieldName = state.getString("classifyingFieldName");
374
        
375
        this.offsetXFieldName = state.getString("offsetXFieldName");
376
        this.offsetYFieldName = state.getString("offsetYFieldName");
377
        this.rotationFieldName = state.getString("rotationFieldName");
378
        this.lineToOffsetColorFieldlName = state.getString("lineToOffsetColorFieldlName");
379

    
380
        this.imagesTableName = state.getString("imagesTableName");
381
        this.imagesTableClassifyingFieldName = state.getString("imagesTableClassifyingFieldName");
382
        this.imageFieldName = state.getString("imageFieldName");
383
        this.imageSelectedFieldName = state.getString("imageSelectedFieldName");
384
        
385
        setZSort(new MyZSort());
386

    
387
        
388
    }
389

    
390
    @Override
391
    public void saveToState(PersistentState state) throws PersistenceException {
392
        super.saveToState(state);
393
        
394
        state.set("scale", this.scale);
395
        state.set("size", this.size);
396
        state.set("units", this.units);
397
        state.set("lineToOffsetColor", this.lineToOffsetColor);
398
        state.set("drawLineToOffset", this.drawLineToOffset);
399
        state.set("reverseDirectionOfAngle", this.reverseDirectionOfAngle);
400
        state.set("classifyingFieldName", this.classifyingFieldName);
401

    
402
        state.set("offsetXFieldName", this.offsetXFieldName);
403
        state.set("offsetYFieldName", this.offsetYFieldName);
404
        state.set("rotationFieldName", this.rotationFieldName);
405
        state.set("lineToOffsetColorFieldlName", this.lineToOffsetColorFieldlName);
406

    
407
        state.set("imagesTableName", this.imagesTableName);
408
        state.set("imagesTableClassifyingFieldName", this.imagesTableClassifyingFieldName);
409
        state.set("imageFieldName", this.imageFieldName);
410
        state.set("imageSelectedFieldName", this.imageSelectedFieldName);
411
        
412
    }
413

    
414
    @Override
415
    protected String[] getRequiredFeatureAttributeNames(FeatureStore fs) throws DataException {
416
        List<String> attributes = new ArrayList<>();
417
        if( StringUtils.isNotBlank(this.classifyingFieldName)) {
418
            attributes.add(this.classifyingFieldName);
419
        }
420
        if( StringUtils.isNotBlank(this.offsetXFieldName)) {
421
            attributes.add(this.offsetXFieldName);
422
        }
423
        if( StringUtils.isNotBlank(this.offsetYFieldName)) {
424
            attributes.add(this.offsetYFieldName);
425
        }
426
        if( StringUtils.isNotBlank(this.rotationFieldName)) {
427
            attributes.add(this.rotationFieldName);
428
        }
429
        if( StringUtils.isNotBlank(this.lineToOffsetColorFieldlName)) {
430
            attributes.add(this.lineToOffsetColorFieldlName);
431
        }
432
        attributes.add( fs.getDefaultFeatureType().getDefaultGeometryAttributeName() );
433
        return attributes.toArray(new String[attributes.size()]);
434
    }
435

    
436
    @Override
437
    public Color getDefaultLineToOffsetColor() {
438
        return this.lineToOffsetColor;
439
    }
440

    
441
    @Override
442
    public void setDefaultLineToOffsetColor(Color color) {
443
        this.lineToOffsetColor = color;
444
    }
445

    
446
    @Override
447
    public boolean isDrawLineToOffset() {
448
        return this.drawLineToOffset;
449
    }
450

    
451
    @Override
452
    public void setDrawLineToOffset(boolean drawLineToOffset) {
453
        this.drawLineToOffset = drawLineToOffset;
454
    }
455

    
456
    @Override
457
    public double getImageSize() {
458
        return this.size;
459
    }
460

    
461
    @Override
462
    public void setImageSize(double size) {
463
        this.size = size;
464
    }
465

    
466
    @Override
467
    public String getLineToOffsetColorFieldName() {
468
        return this.lineToOffsetColorFieldlName;
469
    }
470

    
471
    @Override
472
    public void setLineToOffsetColorFieldName(String fieldName) {
473
        this.lineToOffsetColorFieldlName = fieldName;
474
    }
475

    
476
    @Override
477
    public String getOffsetXFieldName() {
478
        return this.offsetXFieldName;
479
    }
480

    
481
    @Override
482
    public void setOffsetXFieldName(String fieldName) {
483
        this.offsetXFieldName = fieldName;
484
    }
485

    
486
    @Override
487
    public String getOffsetYFieldName() {
488
        return this.offsetYFieldName;
489
    }
490

    
491
    @Override
492
    public void setOffsetYFieldName(String fieldName) {
493
        this.offsetYFieldName = fieldName;
494
    }
495

    
496
    @Override
497
    public String getRotationFieldName() {
498
        return this.rotationFieldName;
499
    }
500

    
501
    @Override
502
    public void setRotationFieldName(String fieldName) {
503
        this.rotationFieldName = fieldName;
504
    }
505

    
506
    @Override
507
    public String getImagesTableName() {
508
        return imagesTableName;
509
    }
510

    
511
    @Override
512
    public void setImagesTableName(String imagesTableName) {
513
        this.imagesTableName = imagesTableName;
514
        this.imagesCache.clear();
515
    }
516

    
517
    @Override
518
    public String getImageFieldName() {
519
        return imageFieldName;
520
    }
521

    
522
    @Override
523
    public void setImageFieldName(String imageFieldName) {
524
        this.imageFieldName = imageFieldName;
525
        this.imagesCache.clear();
526
    }
527

    
528
    @Override
529
    public String getClassifyingFieldName() {
530
        return classifyingFieldName;
531
    }
532

    
533
    @Override
534
    public void setClassifyingFieldName(String classifyingFieldName) {
535
        this.classifyingFieldName = classifyingFieldName;
536
        this.imagesCache.clear();
537
    }
538

    
539
    @Override
540
    public String getImageSelectedFieldName() {
541
        return imageSelectedFieldName;
542
    }
543

    
544
    @Override
545
    public void setImageSelectedFieldName(String imageSelectedFieldName) {
546
        this.imageSelectedFieldName = imageSelectedFieldName;
547
        this.imagesCache.clear();
548
    }
549

    
550
    @Override
551
    public String getImagesTableClassifyingFieldName() {
552
        return imagesTableClassifyingFieldName;
553
    }
554

    
555
    @Override
556
    public void setImagesTableClassifyingFieldName(String imagesTableClassifyingFieldName) {
557
        this.imagesTableClassifyingFieldName = imagesTableClassifyingFieldName;
558
        this.imagesCache.clear();
559
    }
560

    
561
    @Override
562
    public String[] getDescriptions() {
563
        return new String[] { this.imagesTableName + ", "+ this.classifyingFieldName};
564
    }
565

    
566
    @Override
567
    public ISymbol[] getSymbols() {
568
        return new ISymbol[] { this.defaultSymbol };
569
    }
570

    
571
    @Override
572
    public Object[] getValues() {
573
        return new Object[] { "" } ;
574
    }
575

    
576
    @Override
577
    public int getUnits() {
578
        return units;
579
    }
580

    
581
    @Override
582
    public void setUnits(int units) {
583
        this.units = units;
584
    }
585

    
586
    @Override
587
    public double getScale() {
588
        return scale;
589
    }
590

    
591
    @Override
592
    public void setScale(double scale) {
593
        this.scale = scale;
594
    }
595

    
596

    
597
    @Override
598
    public void setReverseDirectionOfAngle(boolean reverse) {
599
        this.reverseDirectionOfAngle = reverse;
600
    }
601

    
602
    @Override
603
    public boolean isReverseDirectionOfAngle() {
604
        return this.reverseDirectionOfAngle;
605
    }
606
    
607
}