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

History | View | Annotate | Download (12.9 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
        public Color getColor() {
78
                /*
79
                 * a multilayer symbol does not define any color, the color
80
                 * of each layer is defined by the layer itself
81
                 */
82
                return null;
83
        }
84

    
85
        public double getRotation() {
86
                return rotation;
87
        }
88

    
89
        public void setColor(Color color) {
90
                /*
91
                 * will apply the color to each layer
92
                 */
93
                for (int i = 0; layers != null && i < layers.length; i++) {
94
                        layers[i].setColor(color);
95
                }
96
        }
97

    
98
        public void setRotation(double rotation) {
99
                this.rotation = rotation;
100
        }
101

    
102
        public double getSize() {
103
                double myMarkerSize = 0;
104

    
105
                for (int i = 0; i < getLayerCount(); i++) {
106
                        myMarkerSize = Math.max(myMarkerSize, ((IMarkerSymbol) getLayer(i)).getSize());
107
                }
108

    
109
                if (markerSize != myMarkerSize) {
110
                        markerSize = myMarkerSize;
111
                }
112
                return markerSize;
113
        }
114

    
115
        public void setSize(double size) {
116
                if (size > 0 && size != getSize()) {
117

    
118
                        double scale = size / getSize();
119
                        this.markerSize = size;
120
                        for (int i = 0; layers != null && i < layers.length; i++) {
121
                                double lSize = layers[i].getSize();
122
                                layers[i].setSize(lSize*scale);
123
                        }
124
                }
125
        }
126

    
127

    
128

    
129
        public void draw(Graphics2D g, AffineTransform affineTransform,
130
                        Geometry geom, Feature feature, Cancellable cancel) {
131
                Point p = (Point) geom;
132
                g.rotate(rotation, p.getX(), p.getY());
133
                for (int i = 0; (cancel == null || !cancel.isCanceled())
134
                                && layers != null && i < layers.length; i++) {
135
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
136
                }
137
                g.rotate(-rotation, p.getX(), p.getY());
138
        }
139

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

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

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

    
165
        public ISymbol getSymbolForSelection() {
166
                if (selectionSymbol == null) {
167
                        selectionSymbol = new MultiLayerMarkerSymbol();
168
                        selectionSymbol.setDescription(getDescription());
169
                        for (int i = 0; layers != null && i < layers.length; i++) {
170
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
171
                        }
172
                }
173
                return selectionSymbol;
174

    
175
        }
176

    
177
        public boolean isSuitableFor(Geometry geom) {
178
                return geom.getType() == Geometry.TYPES.POINT;
179
        }
180

    
181

    
182
        public String getClassName() {
183
                return getClass().getName();
184
        }
185

    
186
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
187
                for (int i = 0; layers != null && i < layers.length; i++) {
188
                        layers[i].print(g, at, geom, properties);
189
                }
190

    
191
        }
192

    
193
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
194
                layers[index] = (IMarkerSymbol) layer;
195
        }
196

    
197
        public void swapLayers(int index1, int index2) {
198
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
199
                layers[index2] = (IMarkerSymbol) aux1;
200
                layers[index1] = (IMarkerSymbol) aux2;
201
        }
202

    
203
        public ISymbol getLayer(int layerIndex) {
204
//                try{
205
                        return layers[layerIndex];
206
//                } catch (Exception e) {
207
//                        return null;
208
//                }
209
        }
210

    
211
        public int getLayerCount() {
212
                return layers.length;
213
        }
214

    
215
        public void addLayer(ISymbol newLayer) {
216
                addLayer(newLayer, layers.length);
217
        }
218

    
219
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
220
                if (newLayer == null ) {
221
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
222
                }
223

    
224
                IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
225
                if (getLayerCount() == 0) {
226
                        // apply the new layer properties to this multilayer
227

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

    
258
        public boolean removeLayer(ISymbol layer) {
259

    
260
                int capacity = 0;
261
                capacity = layers.length;
262
                List<ISymbol> lst = new ArrayList<ISymbol>(capacity);
263
                for (int i = 0; i < capacity; i++) {
264
                        lst.add(layers[i]);
265
                }
266
                boolean contains = lst.remove(layer);
267
                layers = (IMarkerSymbol[])lst.toArray(new IMarkerSymbol[0]);
268
                return contains;
269
        }
270

    
271
        public void setUnit(int unit) {
272
                super.setUnit(unit);
273
                for (int i = 0; layers != null && i < layers.length; i++) {
274
                        layers[i].setUnit(unit);
275
                }
276
        }
277

    
278
        public void setReferenceSystem(int system) {
279
                super.setReferenceSystem(system);
280
                for (int i = 0; layers != null && i < layers.length; i++) {
281
                        layers[i].setReferenceSystem(system);
282
                }
283
        }
284

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

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

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

    
319
        }
320

    
321
        public Object clone() throws CloneNotSupportedException {
322
                MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
323

    
324
                // Clone layers
325
                if (layers != null) {
326
                        IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
327
                        for (int i = 0; i < layers.length; i++) {
328
                                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
329
                        }
330
                        copy.layers = layersCopy;
331
                }
332

    
333
                // Clone selection
334
                if (selectionSymbol != null) {
335
                        copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
336
                                        .clone();
337
                }
338

    
339
                return copy;
340
        }
341

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

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

    
367
        public static class RegisterPersistence implements Callable {
368

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

    
382
                                // Layers
383
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IMarkerSymbol.class);
384
                                // Rotation
385
                                definition.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
386
                        }
387
                        return Boolean.TRUE;
388
                }
389
                
390
        }
391

    
392
        public static class RegisterSymbol implements Callable {
393

    
394
                public Object call() throws Exception {
395
                        int[] shapeTypes;
396
                        SymbolManager manager = MapContextLocator.getSymbolManager();
397

    
398
                shapeTypes =
399
                    new int[] { Geometry.TYPES.POINT, Geometry.TYPES.MULTIPOINT };
400
                manager.registerMultiLayerSymbol(IMarkerSymbol.SYMBOL_NAME,
401
                    shapeTypes,
402
                    MultiLayerMarkerSymbol.class);
403

    
404
                        return Boolean.TRUE;
405
                }
406
                
407
        }
408

    
409
}