Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / marker / impl / MultiLayerMarkerSymbol.java @ 47476

History | View | Annotate | Download (16.6 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 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 3
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.symbology.fmap.mapcontext.rendering.symbol.marker.impl;
25

    
26
import java.awt.Color;
27
import java.awt.Graphics2D;
28
import java.awt.Rectangle;
29
import java.awt.geom.AffineTransform;
30
import java.util.ArrayList;
31
import java.util.Arrays;
32
import java.util.List;
33
import org.gvsig.compat.print.PrintAttributes;
34
import org.gvsig.fmap.dal.feature.Feature;
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.primitive.Point;
37
import org.gvsig.fmap.mapcontext.MapContextLocator;
38
import org.gvsig.fmap.mapcontext.ViewPort;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
40
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
41
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
42
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol_v2;
45
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMultiLayerMarkerSymbol;
46
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.dynobject.DynStruct;
48
import org.gvsig.tools.persistence.PersistenceManager;
49
import org.gvsig.tools.persistence.PersistentState;
50
import org.gvsig.tools.persistence.exception.PersistenceException;
51
import org.gvsig.tools.task.Cancellable;
52
import org.gvsig.tools.util.Callable;
53

    
54
/**
55
 * MultiLayerMarkerSymbol allows to group several marker symbols
56
 * (xxxMarkerSymbol implementing IMarkerSymbol)in one and treat it as an only
57
 * one symbol.
58
 *
59
 * @author gvSIG team
60
 */
61
@SuppressWarnings("UseSpecificCatch")
62
public class MultiLayerMarkerSymbol extends AbstractMarkerSymbol implements IMarkerSymbol, IMultiLayerSymbol, IMultiLayerMarkerSymbol {
63

    
64
    public static final String MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerMarkerSymbol";
65

    
66
    private static final String FIELD_LAYERS = "layers";
67
    private static final String FIELD_ROTATION = "rotation";
68

    
69
    private IMarkerSymbol[] layers = new IMarkerSymbol[0];
70
    private MultiLayerMarkerSymbol selectionSymbol;
71
    private double markerSize;
72
    private double rotation;
73

    
74
    public MultiLayerMarkerSymbol() {
75
        super();
76
    }
77

    
78
    @Override
79
    public Color getColor() {
80
        /*
81
                 * a multilayer symbol does not define any color, the color
82
                 * of each layer is defined by the layer itself
83
         */
84
        return null;
85
    }
86

    
87
    @Override
88
    public double getRotation() {
89
        return rotation;
90
    }
91

    
92
    @Override
93
    public void setColor(Color color) {
94
        for (int i = 0; layers != null && i < layers.length; i++) {
95
            if (layers[i] == null) {
96
                continue;
97
            }
98
            layers[i].setColor(color);
99
        }
100
    }
101

    
102
    @Override
103
    public void setRotation(double rotation) {
104
        this.rotation = rotation;
105
    }
106

    
107
    @Override
108
    public double getSize() {
109
        double myMarkerSize = 0;
110

    
111
        for (int i = 0; i < getLayerCount(); i++) {
112
            ISymbol layer = getLayer(i);
113
            if (layer == null) {
114
                continue;
115
            }
116
            myMarkerSize = Math.max(myMarkerSize, ((IMarkerSymbol) layer).getSize());
117
        }
118

    
119
        if (markerSize != myMarkerSize) {
120
            markerSize = myMarkerSize;
121
        }
122
        return markerSize;
123
    }
124

    
125
    @Override
126
    public void setSize(double size) {
127
        if (size > 0 && size != getSize()) {
128

    
129
            double scale = size / getSize();
130
            this.markerSize = size;
131
            for (int i = 0; layers != null && i < layers.length; i++) {
132
                if (layers[i] == null) {
133
                    continue;
134
                }
135
                double lSize = layers[i].getSize();
136
                layers[i].setSize(lSize * scale);
137
            }
138
        }
139
    }
140

    
141
    @Override
142
    public void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Feature f, Cancellable cancel, Rectangle r) {
143
        if(r!=null){
144
            geom = this.getSampleGeometry(r);
145
        }
146

    
147
        Point p;
148
        try {
149
            p = geom.centroid();
150
        } catch (Exception ex) {
151
            return;
152
        }
153
        g.rotate(rotation, p.getX(), p.getY());
154
        for (int i = 0; (cancel == null || !cancel.isCanceled())
155
                && layers != null && i < layers.length; i++) {
156
            IMarkerSymbol layer = layers[i];
157
            if (layer == null) {
158
                continue;
159
            }
160
            layer.setCartographicContext(this.getCartographicContext());
161
            if(layer instanceof IMarkerSymbol_v2){
162
                ((IMarkerSymbol_v2)layer).draw(g, affineTransform, geom, f, cancel, r);
163
            } else {
164
                layer.draw(g, affineTransform, geom, f, cancel);
165
            }
166
        }
167
        g.rotate(-rotation, p.getX(), p.getY());
168
    }
169

    
170
//    @Override
171
//    public int getOnePointRgb() {
172
//        // will paint only the last layer pixel
173
//        return layers[layers.length - 1].getOnePointRgb();
174
//    }
175
//
176
//    @Override
177
//    public void getPixExtentPlus(Geometry geom, float[] distances,
178
//            ViewPort viewPort, int dpi) {
179
//        float[] myDistances = new float[]{0, 0};
180
//        distances[0] = 0;
181
//        distances[1] = 0;
182
//        for (int i = 0; layers != null && i < layers.length; i++) {
183
//            if (layers[i] == null) {
184
//                continue;
185
//            }
186
//            layers[i].getPixExtentPlus(geom, myDistances, viewPort, dpi);
187
//            distances[0] = Math.max(myDistances[0], distances[0]);
188
//            distances[1] = Math.max(myDistances[1], distances[1]);
189
//        }
190
//    }
191

    
192
    @Override
193
    public ISymbol getSymbolForSelection() {
194
        if (selectionSymbol == null) {
195
            selectionSymbol = new MultiLayerMarkerSymbol();
196
            selectionSymbol.setDescription(getDescription());
197
            for (int i = 0; layers != null && i < layers.length; i++) {
198
                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
199
            }
200
        } else {
201
            for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
202
                selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
203
            }
204
        }
205
        if (selectionSymbol instanceof CartographicSupport) {
206
            ((CartographicSupport) selectionSymbol).setUnit(this.getUnit());
207
        }
208
        return selectionSymbol;
209

    
210
    }
211

    
212
    @Override
213
    public boolean isSuitableFor(Geometry geom) {
214
        return geom.getType() == Geometry.TYPES.POINT;
215
    }
216

    
217
    public String getClassName() {
218
        return getClass().getName();
219
    }
220

    
221
    @Override
222
    public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
223
        for (int i = 0; layers != null && i < layers.length; i++) {
224
            if (layers[i] == null) {
225
                continue;
226
            }
227
            layers[i].print(g, at, geom, properties);
228
        }
229

    
230
    }
231

    
232
    @Override
233
    public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
234
        layers[index] = (IMarkerSymbol) layer;
235
    }
236

    
237
    @Override
238
    public void swapLayers(int index1, int index2) {
239
        ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
240
        layers[index2] = (IMarkerSymbol) aux1;
241
        layers[index1] = (IMarkerSymbol) aux2;
242
    }
243

    
244
    @Override
245
    public ISymbol getLayer(int layerIndex) {
246
        return layers[layerIndex];
247
    }
248

    
249
    @Override
250
    public int getLayerCount() {
251
        return layers.length;
252
    }
253

    
254
    @Override
255
    public void addLayer(ISymbol newLayer) {
256
        addLayer(newLayer, layers.length);
257
    }
258

    
259
    @Override
260
    public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
261
        if (newLayer == null) {
262
            /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
263
        }
264

    
265
        if(!(newLayer instanceof IMarkerSymbol_v2)){
266
            LOGGER.info("Symbol "+newLayer.getClass().getName()+" does not implement IMarkerSymbol_v2");
267
        }
268
        IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
269
        if (getLayerCount() == 0) {
270
            // apply the new layer properties to this multilayer
271

    
272
            setReferenceSystem(newMarker.getReferenceSystem());
273
            markerSize = newMarker.getSize();
274
            //setSize(newMarker.getSize());
275
            setUnit(newMarker.getUnit());
276
        } else {
277
            if (newMarker.getSize() > getSize()) {
278
                //setSize(newMarker.getSize());
279
                markerSize = newMarker.getSize();
280
            }
281
            newMarker.setReferenceSystem(getReferenceSystem());
282
            newMarker.setUnit(getUnit());
283
        }
284
        selectionSymbol = null;
285
        /* forces the selection symbol to be re-created
286
         * next time it is required
287
         */
288
        if (layerIndex < 0 || layers.length < layerIndex) {
289
            throw new IndexOutOfBoundsException(layerIndex + " < 0 or " + layerIndex + " > " + layers.length);
290
        }
291
        List<IMarkerSymbol> newLayers = new ArrayList<>();
292
        newLayers.addAll(Arrays.asList(layers));
293
        try {
294
            newLayers.add(layerIndex, (IMarkerSymbol) newLayer);
295
            layers = (IMarkerSymbol[]) newLayers.toArray(new IMarkerSymbol[newLayers.size()]);
296
        } catch (ArrayStoreException asEx) {
297
            throw new ClassCastException(newLayer.getClass().getName() + " is not an IMarkerSymbol");
298
        }
299
    }
300

    
301
    @Override
302
    public boolean removeLayer(ISymbol layer) {
303

    
304
        int capacity;
305
        capacity = layers.length;
306
        List<IMarkerSymbol> lst = new ArrayList<>(capacity);
307
        for (int i = 0; i < capacity; i++) {
308
            lst.add(layers[i]);
309
        }
310
        boolean contains = lst.remove((IMarkerSymbol)layer);
311
        layers = (IMarkerSymbol[]) lst.toArray(new IMarkerSymbol[0]);
312
        return contains;
313
    }
314

    
315
    @Override
316
    public void setUnit(int unit) {
317
        super.setUnit(unit);
318
        for (int i = 0; layers != null && i < layers.length; i++) {
319
            if (layers[i] == null) {
320
                continue;
321
            }
322
            layers[i].setUnit(unit);
323
        }
324
    }
325

    
326
    @Override
327
    public void setReferenceSystem(int system) {
328
        super.setReferenceSystem(system);
329
        for (int i = 0; layers != null && i < layers.length; i++) {
330
            if (layers[i] == null) {
331
                continue;
332
            }
333
            layers[i].setReferenceSystem(system);
334
        }
335
    }
336

    
337
    @Override
338
    public void setAlpha(int alpha) {
339
        // first, get the biggest alpha in the layers and the index if such layer
340
        int maxAlpha = Integer.MIN_VALUE;
341
        int maxAlphaLayerIndex = 0;
342
        for (int i = 0; layers != null && i < layers.length; i++) {
343
            if (layers[i] != null) {
344
                if (layers[i].getColor().getAlpha() > maxAlpha) {
345
                    maxAlpha = layers[i].getColor().getAlpha();
346
                    maxAlphaLayerIndex = i;
347
                }
348
            }
349
        }
350

    
351
        // now, max alpha takes the value of the desired alpha and the rest
352
        // will take a scaled (to biggest alpha) alpha value
353
        for (int i = 0; layers != null && i < layers.length; i++) {
354
            if (layers[i] == null) {
355
                continue;
356
            }
357
            int r = layers[i].getColor().getRed();
358
            int g = layers[i].getColor().getGreen();
359
            int b = layers[i].getColor().getBlue();
360

    
361
            if (i != maxAlphaLayerIndex) {
362
                double scaledAlpha = (double) layers[i].getColor().getAlpha() / maxAlpha;
363
                int myAlpha = (int) (alpha * scaledAlpha);
364
                if (myAlpha == 0) {
365
                    myAlpha = 1;
366
                }
367
                layers[i].setColor(new Color(r, g, b, myAlpha));
368
            } else {
369
                int myAlpha = alpha;
370
                if (myAlpha == 0) {
371
                    myAlpha = 1;
372
                }
373
                layers[i].setColor(new Color(r, g, b, myAlpha));
374
            }
375
        }
376

    
377
    }
378

    
379
    @Override
380
    public Object clone() throws CloneNotSupportedException {
381
        MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
382

    
383
        // Clone layers
384
        if (layers != null) {
385
            IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
386
            for (int i = 0; i < layers.length; i++) {
387
                if (layers[i] == null) {
388
                    continue;
389
                }
390
                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
391
            }
392
            copy.layers = layersCopy;
393
        }
394

    
395
        // Clone selection
396
        if (selectionSymbol != null) {
397
            copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
398
                    .clone();
399
        }
400

    
401
        return copy;
402
    }
403

    
404
    @SuppressWarnings("unchecked")
405
    @Override
406
    public void loadFromState(PersistentState state)
407
            throws PersistenceException {
408
        // Set parent fill symbol properties
409
        super.loadFromState(state);
410
        // Set own properties
411
        List theLayers = state.getList(FIELD_LAYERS);
412
        if (theLayers != null) {
413
            for (int i = 0; i < theLayers.size(); i++) {
414
                Object layer = theLayers.get(i);
415
                if (layer == null) {
416
                    continue;
417
                }
418
                addLayer((ISymbol) layer);
419
            }
420
        }
421
        setRotation(state.getDouble(FIELD_ROTATION));
422
    }
423

    
424
    @Override
425
    public void saveToState(PersistentState state) throws PersistenceException {
426
        // Save parent fill symbol properties
427
        super.saveToState(state);
428
        // Save own properties
429
        if (layers != null && layers.length > 0) {
430
            state.set(FIELD_LAYERS, Arrays.asList(layers));
431
        }
432
        state.set(FIELD_ROTATION, getRotation());
433
    }
434

    
435
    public static class RegisterPersistence implements Callable {
436

    
437
        @Override
438
        public Object call() throws Exception {
439
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
440
            if (manager.getDefinition(MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
441
                DynStruct definition = manager.addDefinition(
442
                        MultiLayerMarkerSymbol.class,
443
                        MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME,
444
                        MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME + " Persistence definition",
445
                        null,
446
                        null
447
                );
448
                // Extend the MarkerSymbol base definition
449
                definition.extend(manager.getDefinition(MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME));
450

    
451
                // Layers
452
                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IMarkerSymbol.class);
453
                // Rotation
454
                definition.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
455
            }
456
            return true;
457
        }
458

    
459
    }
460

    
461
    public static class RegisterSymbol implements Callable {
462

    
463
        @Override
464
        public Object call() throws Exception {
465
            int[] shapeTypes;
466
            SymbolManager manager = MapContextLocator.getSymbolManager();
467

    
468
            shapeTypes = new int[]{Geometry.TYPES.POINT, Geometry.TYPES.MULTIPOINT};
469
            manager.registerMultiLayerSymbol(IMarkerSymbol.SYMBOL_NAME,
470
                    shapeTypes,
471
                    MultiLayerMarkerSymbol.class
472
            );
473
            return true;
474
        }
475

    
476
    }
477

    
478
}