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

History | View | Annotate | Download (13.1 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

    
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

    
65
    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

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

    
77
    @Override
78
        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
                Point p = (Point) geom;
133
                g.rotate(rotation, p.getX(), p.getY());
134
                for (int i = 0; (cancel == null || !cancel.isCanceled())
135
                                && layers != null && i < layers.length; i++) {
136
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
137
                }
138
                g.rotate(-rotation, p.getX(), p.getY());
139
        }
140

    
141
        public void drawInsideRectangle(Graphics2D g, AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
142
                g.rotate(rotation, r.getCenterX(), r.getCenterY());
143
                for (int i = 0; layers != null && i < layers.length; i++) {
144
                        layers[i].drawInsideRectangle(g, scaleInstance, r, properties);
145
                }
146
                g.rotate(-rotation, r.getCenterX(), r.getCenterY());
147
        }
148

    
149
        public int getOnePointRgb() {
150
                // will paint only the last layer pixel
151
                return layers[layers.length-1].getOnePointRgb();
152
        }
153

    
154
        public void getPixExtentPlus(Geometry geom, float[] distances,
155
                        ViewPort viewPort, int dpi) {
156
                float[] myDistances = new float[] {0,0};
157
                distances[0] = 0;
158
                distances[1] = 0;
159
                for (int i = 0; layers != null && i < layers.length; i++) {
160
                        layers[i].getPixExtentPlus(geom, myDistances, viewPort, dpi);
161
                        distances[0] = Math.max(myDistances[0], distances[0]);
162
                        distances[1] = Math.max(myDistances[1], distances[1]);
163
                }
164
        }
165

    
166
        public ISymbol getSymbolForSelection() {
167
                if (selectionSymbol == null) {
168
                        selectionSymbol = new MultiLayerMarkerSymbol();
169
                        selectionSymbol.setDescription(getDescription());
170
                        for (int i = 0; layers != null && i < layers.length; i++) {
171
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
172
                        }
173
                }else {
174
            for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
175
                selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
176
            }
177
        }
178
                return selectionSymbol;
179

    
180
        }
181

    
182
        public boolean isSuitableFor(Geometry geom) {
183
                return geom.getType() == Geometry.TYPES.POINT;
184
        }
185

    
186

    
187
        public String getClassName() {
188
                return getClass().getName();
189
        }
190

    
191
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
192
                for (int i = 0; layers != null && i < layers.length; i++) {
193
                        layers[i].print(g, at, geom, properties);
194
                }
195

    
196
        }
197

    
198
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
199
                layers[index] = (IMarkerSymbol) layer;
200
        }
201

    
202
        public void swapLayers(int index1, int index2) {
203
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
204
                layers[index2] = (IMarkerSymbol) aux1;
205
                layers[index1] = (IMarkerSymbol) aux2;
206
        }
207

    
208
        public ISymbol getLayer(int layerIndex) {
209
//                try{
210
                        return layers[layerIndex];
211
//                } catch (Exception e) {
212
//                        return null;
213
//                }
214
        }
215

    
216
        public int getLayerCount() {
217
                return layers.length;
218
        }
219

    
220
        public void addLayer(ISymbol newLayer) {
221
                addLayer(newLayer, layers.length);
222
        }
223

    
224
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
225
                if (newLayer == null ) {
226
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
227
                }
228

    
229
                IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
230
                if (getLayerCount() == 0) {
231
                        // apply the new layer properties to this multilayer
232

    
233
                        setReferenceSystem(newMarker.getReferenceSystem());
234
                        markerSize = newMarker.getSize();
235
                        //setSize(newMarker.getSize());
236
                        setUnit(newMarker.getUnit());
237
                } else {
238
                        if (newMarker.getSize() > getSize()) {
239
                                //setSize(newMarker.getSize());
240
                                markerSize = newMarker.getSize();
241
                        }
242
                        newMarker.setReferenceSystem(getReferenceSystem());
243
                        newMarker.setUnit(getUnit());
244
                }
245
                selectionSymbol = null; /* forces the selection symbol to be re-created
246
                                                                  * next time it is required
247
                                                                  */
248
                if (layerIndex < 0 || layers.length < layerIndex) {
249
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
250
                }
251
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
252
                for (int i = 0; i < layers.length; i++) {
253
                        newLayers.add(layers[i]);
254
                }
255
                try {
256
                        newLayers.add(layerIndex, newLayer);
257
                        layers = (IMarkerSymbol[]) newLayers.toArray(new IMarkerSymbol[0]);
258
                } catch (ArrayStoreException asEx) {
259
                        throw new ClassCastException(newLayer.getClass().getName()+" is not an IMarkerSymbol");
260
                }
261
        }
262

    
263
        public boolean removeLayer(ISymbol layer) {
264

    
265
                int capacity = 0;
266
                capacity = layers.length;
267
                List<ISymbol> lst = new ArrayList<ISymbol>(capacity);
268
                for (int i = 0; i < capacity; i++) {
269
                        lst.add(layers[i]);
270
                }
271
                boolean contains = lst.remove(layer);
272
                layers = (IMarkerSymbol[])lst.toArray(new IMarkerSymbol[0]);
273
                return contains;
274
        }
275

    
276
        public void setUnit(int unit) {
277
                super.setUnit(unit);
278
                for (int i = 0; layers != null && i < layers.length; i++) {
279
                        layers[i].setUnit(unit);
280
                }
281
        }
282

    
283
        public void setReferenceSystem(int system) {
284
                super.setReferenceSystem(system);
285
                for (int i = 0; layers != null && i < layers.length; i++) {
286
                        layers[i].setReferenceSystem(system);
287
                }
288
        }
289

    
290
        public void setAlpha(int alpha) {
291
                // first, get the biggest alpha in the layers and the index if such layer
292
                int maxAlpha = Integer.MIN_VALUE;
293
                int maxAlphaLayerIndex = 0;
294
                for (int i = 0; layers != null && i < layers.length; i++) {
295
                        if (layers[i].getColor().getAlpha() > maxAlpha) {
296
                                maxAlpha = layers[i].getColor().getAlpha();
297
                                maxAlphaLayerIndex = i;
298
                        }
299
                }
300

    
301
                // now, max alpha takes the value of the desired alpha and the rest
302
                // will take a scaled (to biggest alpha) alpha value
303
                for (int i = 0; layers != null && i < layers.length; i++) {
304
                        int r = layers[i].getColor().getRed();
305
                        int g = layers[i].getColor().getGreen();
306
                        int b = layers[i].getColor().getBlue();
307

    
308
                        if (i!=maxAlphaLayerIndex) {
309
                                double scaledAlpha = (double) layers[i].getColor().getAlpha()/maxAlpha;
310
                                int myAlpha = (int) (alpha*scaledAlpha);
311
                                if (myAlpha == 0) {
312
                                        myAlpha = 1;
313
                                }
314
                                layers[i].setColor(new Color(r, g, b, myAlpha));
315
                        } else {
316
                                int myAlpha = alpha;
317
                                if (myAlpha == 0) {
318
                                        myAlpha = 1;
319
                                }
320
                                layers[i].setColor(new Color(r, g, b, myAlpha));
321
                        }
322
                }
323

    
324
        }
325

    
326
        public Object clone() throws CloneNotSupportedException {
327
                MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
328

    
329
                // Clone layers
330
                if (layers != null) {
331
                        IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
332
                        for (int i = 0; i < layers.length; i++) {
333
                                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
334
                        }
335
                        copy.layers = layersCopy;
336
                }
337

    
338
                // Clone selection
339
                if (selectionSymbol != null) {
340
                        copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
341
                                        .clone();
342
                }
343

    
344
                return copy;
345
        }
346

    
347
        @SuppressWarnings("unchecked")
348
        public void loadFromState(PersistentState state)
349
                        throws PersistenceException {
350
                // Set parent fill symbol properties
351
                super.loadFromState(state);
352
                // Set own properties
353
                List layers = state.getList(FIELD_LAYERS);
354
                if (layers != null) {
355
                        for (int i = 0; i < layers.size(); i++) {
356
                                addLayer((ISymbol) layers.get(i));
357
                        }
358
                }
359
                setRotation(state.getDouble(FIELD_ROTATION));
360
        }
361

    
362
        public void saveToState(PersistentState state) throws PersistenceException {
363
                // Save parent fill symbol properties
364
                super.saveToState(state);
365
                // Save own properties
366
                if (layers != null && layers.length > 0) {
367
                        state.set(FIELD_LAYERS, Arrays.asList(layers));
368
                }
369
                state.set(FIELD_ROTATION, getRotation());
370
        }
371

    
372
        public static class RegisterPersistence implements Callable {
373

    
374
                public Object call() throws Exception {
375
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
376
                        if( manager.getDefinition(MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
377
                                DynStruct definition = manager.addDefinition(
378
                                                MultiLayerMarkerSymbol.class,
379
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME,
380
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
381
                                                null,
382
                                                null
383
                                );
384
                                // Extend the MarkerSymbol base definition
385
                                definition.extend(manager.getDefinition(MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME));
386

    
387
                                // Layers
388
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IMarkerSymbol.class);
389
                                // Rotation
390
                                definition.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
391
                        }
392
                        return Boolean.TRUE;
393
                }
394

    
395
        }
396

    
397
        public static class RegisterSymbol implements Callable {
398

    
399
                public Object call() throws Exception {
400
                        int[] shapeTypes;
401
                        SymbolManager manager = MapContextLocator.getSymbolManager();
402

    
403
                shapeTypes =
404
                    new int[] { Geometry.TYPES.POINT, Geometry.TYPES.MULTIPOINT };
405
                manager.registerMultiLayerSymbol(IMarkerSymbol.SYMBOL_NAME,
406
                    shapeTypes,
407
                    MultiLayerMarkerSymbol.class);
408

    
409
                        return Boolean.TRUE;
410
                }
411

    
412
        }
413

    
414
}