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 @ 45523

History | View | Annotate | Download (13.2 KB)

1 40560 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40560 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6 40435 jjdelcerro
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8 40560 jjdelcerro
 * as published by the Free Software Foundation; either version 3
9 40435 jjdelcerro
 * of the License, or (at your option) any later version.
10 40560 jjdelcerro
 *
11 40435 jjdelcerro
 * 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 40560 jjdelcerro
 *
16 40435 jjdelcerro
 * 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 40560 jjdelcerro
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 40435 jjdelcerro
 * MA  02110-1301, USA.
20 40560 jjdelcerro
 *
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 40435 jjdelcerro
 */
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
34
import org.gvsig.compat.print.PrintAttributes;
35
import org.gvsig.fmap.dal.feature.Feature;
36
import org.gvsig.fmap.geom.Geometry;
37
import org.gvsig.fmap.geom.primitive.Point;
38
import org.gvsig.fmap.mapcontext.MapContextLocator;
39
import org.gvsig.fmap.mapcontext.ViewPort;
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.SymbolDrawingException;
43
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
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 (xxxMarkerSymbol
56
 * implementing IMarkerSymbol)in one and treat it as an only one symbol.
57
 *
58
 * @author 2005-2008 jaume dominguez faus - jaume.dominguez@iver.es
59
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
60
 */
61
public class MultiLayerMarkerSymbol extends AbstractMarkerSymbol implements IMarkerSymbol, IMultiLayerSymbol, IMultiLayerMarkerSymbol {
62
63
    public static final String MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerMarkerSymbol";
64 42439 dmartinezizquierdo
65 40435 jjdelcerro
    private static final String FIELD_LAYERS = "layers";
66
    private static final String FIELD_ROTATION = "rotation";
67
68
    private IMarkerSymbol[] layers = new IMarkerSymbol[0];
69
        private MultiLayerMarkerSymbol selectionSymbol;
70
        private double markerSize;
71
        private double rotation;
72 42439 dmartinezizquierdo
73 40435 jjdelcerro
        public MultiLayerMarkerSymbol() {
74
                super();
75
        }
76 42439 dmartinezizquierdo
77 42811 jjdelcerro
    @Override
78 40435 jjdelcerro
        public Color getColor() {
79
                /*
80
                 * a multilayer symbol does not define any color, the color
81
                 * of each layer is defined by the layer itself
82
                 */
83
                return null;
84
        }
85
86
        public double getRotation() {
87
                return rotation;
88
        }
89
90
        public void setColor(Color color) {
91
                /*
92
                 * will apply the color to each layer
93
                 */
94
                for (int i = 0; layers != null && i < layers.length; i++) {
95
                        layers[i].setColor(color);
96
                }
97
        }
98
99
        public void setRotation(double rotation) {
100
                this.rotation = rotation;
101
        }
102
103
        public double getSize() {
104
                double myMarkerSize = 0;
105
106
                for (int i = 0; i < getLayerCount(); i++) {
107
                        myMarkerSize = Math.max(myMarkerSize, ((IMarkerSymbol) getLayer(i)).getSize());
108
                }
109
110
                if (markerSize != myMarkerSize) {
111
                        markerSize = myMarkerSize;
112
                }
113
                return markerSize;
114
        }
115
116
        public void setSize(double size) {
117
                if (size > 0 && size != getSize()) {
118
119
                        double scale = size / getSize();
120
                        this.markerSize = size;
121
                        for (int i = 0; layers != null && i < layers.length; i++) {
122
                                double lSize = layers[i].getSize();
123
                                layers[i].setSize(lSize*scale);
124
                        }
125
                }
126
        }
127
128
129
130
        public void draw(Graphics2D g, AffineTransform affineTransform,
131
                        Geometry geom, Feature feature, Cancellable cancel) {
132 43491 jjdelcerro
        Point p;
133
        try {
134
            p = geom.centroid();
135
        } catch(Exception ex) {
136
            return;
137
        }
138 40435 jjdelcerro
                g.rotate(rotation, p.getX(), p.getY());
139
                for (int i = 0; (cancel == null || !cancel.isCanceled())
140
                                && layers != null && i < layers.length; i++) {
141
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
142
                }
143
                g.rotate(-rotation, p.getX(), p.getY());
144
        }
145
146
        public void drawInsideRectangle(Graphics2D g, AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
147
                g.rotate(rotation, r.getCenterX(), r.getCenterY());
148
                for (int i = 0; layers != null && i < layers.length; i++) {
149
                        layers[i].drawInsideRectangle(g, scaleInstance, r, properties);
150
                }
151
                g.rotate(-rotation, r.getCenterX(), r.getCenterY());
152
        }
153
154
        public int getOnePointRgb() {
155
                // will paint only the last layer pixel
156
                return layers[layers.length-1].getOnePointRgb();
157
        }
158
159
        public void getPixExtentPlus(Geometry geom, float[] distances,
160
                        ViewPort viewPort, int dpi) {
161
                float[] myDistances = new float[] {0,0};
162
                distances[0] = 0;
163
                distances[1] = 0;
164
                for (int i = 0; layers != null && i < layers.length; i++) {
165
                        layers[i].getPixExtentPlus(geom, myDistances, viewPort, dpi);
166
                        distances[0] = Math.max(myDistances[0], distances[0]);
167
                        distances[1] = Math.max(myDistances[1], distances[1]);
168
                }
169
        }
170
171
        public ISymbol getSymbolForSelection() {
172
                if (selectionSymbol == null) {
173
                        selectionSymbol = new MultiLayerMarkerSymbol();
174
                        selectionSymbol.setDescription(getDescription());
175
                        for (int i = 0; layers != null && i < layers.length; i++) {
176
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
177
                        }
178 42439 dmartinezizquierdo
                }else {
179
            for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
180
                selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
181
            }
182
        }
183 40435 jjdelcerro
                return selectionSymbol;
184
185
        }
186
187
        public boolean isSuitableFor(Geometry geom) {
188
                return geom.getType() == Geometry.TYPES.POINT;
189
        }
190
191
192
        public String getClassName() {
193
                return getClass().getName();
194
        }
195
196
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
197
                for (int i = 0; layers != null && i < layers.length; i++) {
198
                        layers[i].print(g, at, geom, properties);
199
                }
200
201
        }
202
203
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
204
                layers[index] = (IMarkerSymbol) layer;
205
        }
206
207
        public void swapLayers(int index1, int index2) {
208
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
209
                layers[index2] = (IMarkerSymbol) aux1;
210
                layers[index1] = (IMarkerSymbol) aux2;
211
        }
212
213
        public ISymbol getLayer(int layerIndex) {
214
//                try{
215
                        return layers[layerIndex];
216
//                } catch (Exception e) {
217
//                        return null;
218
//                }
219
        }
220
221
        public int getLayerCount() {
222
                return layers.length;
223
        }
224
225
        public void addLayer(ISymbol newLayer) {
226
                addLayer(newLayer, layers.length);
227
        }
228
229
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
230
                if (newLayer == null ) {
231
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
232
                }
233
234
                IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
235
                if (getLayerCount() == 0) {
236
                        // apply the new layer properties to this multilayer
237
238
                        setReferenceSystem(newMarker.getReferenceSystem());
239
                        markerSize = newMarker.getSize();
240
                        //setSize(newMarker.getSize());
241
                        setUnit(newMarker.getUnit());
242
                } else {
243
                        if (newMarker.getSize() > getSize()) {
244
                                //setSize(newMarker.getSize());
245
                                markerSize = newMarker.getSize();
246
                        }
247
                        newMarker.setReferenceSystem(getReferenceSystem());
248
                        newMarker.setUnit(getUnit());
249
                }
250
                selectionSymbol = null; /* forces the selection symbol to be re-created
251
                                                                  * next time it is required
252
                                                                  */
253
                if (layerIndex < 0 || layers.length < layerIndex) {
254
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
255
                }
256
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
257
                for (int i = 0; i < layers.length; i++) {
258
                        newLayers.add(layers[i]);
259
                }
260
                try {
261
                        newLayers.add(layerIndex, newLayer);
262
                        layers = (IMarkerSymbol[]) newLayers.toArray(new IMarkerSymbol[0]);
263
                } catch (ArrayStoreException asEx) {
264
                        throw new ClassCastException(newLayer.getClass().getName()+" is not an IMarkerSymbol");
265
                }
266
        }
267
268
        public boolean removeLayer(ISymbol layer) {
269
270
                int capacity = 0;
271
                capacity = layers.length;
272
                List<ISymbol> lst = new ArrayList<ISymbol>(capacity);
273
                for (int i = 0; i < capacity; i++) {
274
                        lst.add(layers[i]);
275
                }
276
                boolean contains = lst.remove(layer);
277
                layers = (IMarkerSymbol[])lst.toArray(new IMarkerSymbol[0]);
278
                return contains;
279
        }
280
281
        public void setUnit(int unit) {
282
                super.setUnit(unit);
283
                for (int i = 0; layers != null && i < layers.length; i++) {
284
                        layers[i].setUnit(unit);
285
                }
286
        }
287
288
        public void setReferenceSystem(int system) {
289
                super.setReferenceSystem(system);
290
                for (int i = 0; layers != null && i < layers.length; i++) {
291
                        layers[i].setReferenceSystem(system);
292
                }
293
        }
294
295
        public void setAlpha(int alpha) {
296
                // first, get the biggest alpha in the layers and the index if such layer
297
                int maxAlpha = Integer.MIN_VALUE;
298
                int maxAlphaLayerIndex = 0;
299
                for (int i = 0; layers != null && i < layers.length; i++) {
300
                        if (layers[i].getColor().getAlpha() > maxAlpha) {
301
                                maxAlpha = layers[i].getColor().getAlpha();
302
                                maxAlphaLayerIndex = i;
303
                        }
304
                }
305
306
                // now, max alpha takes the value of the desired alpha and the rest
307
                // will take a scaled (to biggest alpha) alpha value
308
                for (int i = 0; layers != null && i < layers.length; i++) {
309
                        int r = layers[i].getColor().getRed();
310
                        int g = layers[i].getColor().getGreen();
311
                        int b = layers[i].getColor().getBlue();
312
313
                        if (i!=maxAlphaLayerIndex) {
314
                                double scaledAlpha = (double) layers[i].getColor().getAlpha()/maxAlpha;
315
                                int myAlpha = (int) (alpha*scaledAlpha);
316
                                if (myAlpha == 0) {
317
                                        myAlpha = 1;
318
                                }
319
                                layers[i].setColor(new Color(r, g, b, myAlpha));
320
                        } else {
321
                                int myAlpha = alpha;
322
                                if (myAlpha == 0) {
323
                                        myAlpha = 1;
324
                                }
325
                                layers[i].setColor(new Color(r, g, b, myAlpha));
326
                        }
327
                }
328
329
        }
330
331
        public Object clone() throws CloneNotSupportedException {
332
                MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
333
334
                // Clone layers
335
                if (layers != null) {
336
                        IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
337
                        for (int i = 0; i < layers.length; i++) {
338
                                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
339
                        }
340
                        copy.layers = layersCopy;
341
                }
342
343
                // Clone selection
344
                if (selectionSymbol != null) {
345
                        copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
346
                                        .clone();
347
                }
348
349
                return copy;
350
        }
351
352
        @SuppressWarnings("unchecked")
353
        public void loadFromState(PersistentState state)
354
                        throws PersistenceException {
355
                // Set parent fill symbol properties
356
                super.loadFromState(state);
357
                // Set own properties
358
                List layers = state.getList(FIELD_LAYERS);
359
                if (layers != null) {
360
                        for (int i = 0; i < layers.size(); i++) {
361
                                addLayer((ISymbol) layers.get(i));
362
                        }
363
                }
364
                setRotation(state.getDouble(FIELD_ROTATION));
365
        }
366
367
        public void saveToState(PersistentState state) throws PersistenceException {
368
                // Save parent fill symbol properties
369
                super.saveToState(state);
370
                // Save own properties
371
                if (layers != null && layers.length > 0) {
372
                        state.set(FIELD_LAYERS, Arrays.asList(layers));
373
                }
374
                state.set(FIELD_ROTATION, getRotation());
375
        }
376
377
        public static class RegisterPersistence implements Callable {
378
379
                public Object call() throws Exception {
380
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
381
                        if( manager.getDefinition(MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
382
                                DynStruct definition = manager.addDefinition(
383
                                                MultiLayerMarkerSymbol.class,
384
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME,
385
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
386 42439 dmartinezizquierdo
                                                null,
387 40435 jjdelcerro
                                                null
388
                                );
389
                                // Extend the MarkerSymbol base definition
390
                                definition.extend(manager.getDefinition(MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME));
391
392
                                // Layers
393
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IMarkerSymbol.class);
394
                                // Rotation
395
                                definition.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
396
                        }
397
                        return Boolean.TRUE;
398
                }
399 42439 dmartinezizquierdo
400 40435 jjdelcerro
        }
401
402
        public static class RegisterSymbol implements Callable {
403
404
                public Object call() throws Exception {
405
                        int[] shapeTypes;
406
                        SymbolManager manager = MapContextLocator.getSymbolManager();
407
408
                shapeTypes =
409
                    new int[] { Geometry.TYPES.POINT, Geometry.TYPES.MULTIPOINT };
410
                manager.registerMultiLayerSymbol(IMarkerSymbol.SYMBOL_NAME,
411
                    shapeTypes,
412
                    MultiLayerMarkerSymbol.class);
413
414
                        return Boolean.TRUE;
415
                }
416 42439 dmartinezizquierdo
417 40435 jjdelcerro
        }
418
419
}