Statistics
| Revision:

root / tags / v2_0_0_Build_2021 / extensions / org.gvsig.symbology / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / marker / impl / MultiLayerMarkerSymbol.java @ 34111

History | View | Annotate | Download (13.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.impl;
23

    
24
import java.awt.Color;
25
import java.awt.Graphics2D;
26
import java.awt.Rectangle;
27
import java.awt.geom.AffineTransform;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.List;
31

    
32
import org.gvsig.compat.print.PrintAttributes;
33
import org.gvsig.fmap.dal.feature.Feature;
34
import org.gvsig.fmap.geom.Geometry;
35
import org.gvsig.fmap.geom.primitive.Point;
36
import org.gvsig.fmap.mapcontext.MapContextLocator;
37
import org.gvsig.fmap.mapcontext.ViewPort;
38
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
40
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
41
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
42
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
43
import org.gvsig.tools.ToolsLocator;
44
import org.gvsig.tools.dynobject.DynStruct;
45
import org.gvsig.tools.persistence.PersistenceManager;
46
import org.gvsig.tools.persistence.PersistentState;
47
import org.gvsig.tools.persistence.exception.PersistenceException;
48
import org.gvsig.tools.task.Cancellable;
49
import org.gvsig.tools.util.Callable;
50
import org.gvsig.utils.XMLEntity;
51
import org.gvsig.utils.XMLException;
52

    
53
/**
54
 * MultiLayerMarkerSymbol allows to group several marker symbols (xxxMarkerSymbol
55
 * implementing IMarkerSymbol)in one and treat it as an only one symbol.
56
 *
57
 * @author 2005-2008 jaume dominguez faus - jaume.dominguez@iver.es
58
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
59
 */
60
public class MultiLayerMarkerSymbol extends AbstractMarkerSymbol implements IMarkerSymbol, IMultiLayerSymbol {
61

    
62
    public static final String MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerMarkerSymbol";
63
    
64
    private static final String FIELD_LAYERS = "layers";
65
    private static final String FIELD_ROTATION = "rotation";
66

    
67
    private IMarkerSymbol[] layers = new IMarkerSymbol[0];
68
        private MultiLayerMarkerSymbol selectionSymbol;
69
        private double markerSize;
70
        private double rotation;
71
        
72
        public MultiLayerMarkerSymbol() {
73
                super();
74
        }
75
        
76
        public Color getColor() {
77
                /*
78
                 * a multilayer symbol does not define any color, the color
79
                 * of each layer is defined by the layer itself
80
                 */
81
                return null;
82
        }
83

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

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

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

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

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

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

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

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

    
126

    
127

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

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

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

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

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

    
174
        }
175

    
176

    
177
        public XMLEntity getXMLEntity() throws XMLException {
178
                XMLEntity xml = new XMLEntity();
179

    
180
//                xml.putProperty("className", getClass().getName());
181
//                xml.putProperty("isShapeVisible", isShapeVisible());
182
//                xml.putProperty("desc", getDescription());
183
//                xml.putProperty("size",        getSize());
184
//                xml.putProperty("unit", getUnit());
185
//                xml.putProperty("referenceSystem", getReferenceSystem());
186
//                for (int i = 0; i < layers.length; i++) {
187
//                        xml.addChild(layers[i].getXMLEntity());
188
//                }
189
                return xml;
190
        }
191

    
192
        public boolean isSuitableFor(Geometry geom) {
193
                return geom.getType() == Geometry.TYPES.POINT;
194
        }
195

    
196

    
197
        public String getClassName() {
198
                return getClass().getName();
199
        }
200

    
201
        /**
202
         * TODO: replace with the new Persistence API
203
         */
204
        public void setXMLEntity(XMLEntity xml) {
205
//                setIsShapeVisible(xml.getBooleanProperty("isShapeVisible"));
206
//                setDescription(xml.getStringProperty("desc"));
207
//                setSize(xml.getDoubleProperty("size"));
208
//                setUnit(xml.getIntProperty("unit"));
209
//                setReferenceSystem(xml.getIntProperty("referenceSystem"));
210
//                for (int i = 0; i < xml.getChildrenCount(); i++) {
211
//                        addLayer(SymbologyFactory.createSymbolFromXML(xml.getChild(i), "layer" + i));
212
//                }
213
        }
214

    
215

    
216
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
217
                for (int i = 0; layers != null && i < layers.length; i++) {
218
                        layers[i].print(g, at, geom, properties);
219
                }
220

    
221
        }
222

    
223
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
224
                layers[index] = (IMarkerSymbol) layer;
225
        }
226

    
227
        public void swapLayers(int index1, int index2) {
228
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
229
                layers[index2] = (IMarkerSymbol) aux1;
230
                layers[index1] = (IMarkerSymbol) aux2;
231
        }
232

    
233
        public ISymbol getLayer(int layerIndex) {
234
//                try{
235
                        return layers[layerIndex];
236
//                } catch (Exception e) {
237
//                        return null;
238
//                }
239
        }
240

    
241
        public int getLayerCount() {
242
                return layers.length;
243
        }
244

    
245
        public void addLayer(ISymbol newLayer) {
246
                addLayer(newLayer, layers.length);
247
        }
248

    
249
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
250
                if (newLayer == null ) {
251
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
252
                }
253

    
254
                IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
255
                if (getLayerCount() == 0) {
256
                        // apply the new layer properties to this multilayer
257

    
258
                        setReferenceSystem(newMarker.getReferenceSystem());
259
                        markerSize = newMarker.getSize();
260
                        //setSize(newMarker.getSize());
261
                        setUnit(newMarker.getUnit());
262
                } else {
263
                        if (newMarker.getSize() > getSize()) {
264
                                //setSize(newMarker.getSize());
265
                                markerSize = newMarker.getSize();
266
                        }
267
                        newMarker.setReferenceSystem(getReferenceSystem());
268
                        newMarker.setUnit(getUnit());
269
                }
270
                selectionSymbol = null; /* forces the selection symbol to be re-created
271
                                                                  * next time it is required
272
                                                                  */
273
                if (layerIndex < 0 || layers.length < layerIndex) {
274
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
275
                }
276
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
277
                for (int i = 0; i < layers.length; i++) {
278
                        newLayers.add(layers[i]);
279
                }
280
                try {
281
                        newLayers.add(layerIndex, newLayer);
282
                        layers = (IMarkerSymbol[]) newLayers.toArray(new IMarkerSymbol[0]);
283
                } catch (ArrayStoreException asEx) {
284
                        throw new ClassCastException(newLayer.getClass().getName()+" is not an IMarkerSymbol");
285
                }
286
        }
287

    
288
        public boolean removeLayer(ISymbol layer) {
289

    
290
                int capacity = 0;
291
                capacity = layers.length;
292
                List<ISymbol> lst = new ArrayList<ISymbol>(capacity);
293
                for (int i = 0; i < capacity; i++) {
294
                        lst.add(layers[i]);
295
                }
296
                boolean contains = lst.remove(layer);
297
                layers = (IMarkerSymbol[])lst.toArray(new IMarkerSymbol[0]);
298
                return contains;
299
        }
300

    
301
        public void setUnit(int unit) {
302
                super.setUnit(unit);
303
                for (int i = 0; layers != null && i < layers.length; i++) {
304
                        layers[i].setUnit(unit);
305
                }
306
        }
307

    
308
        public void setReferenceSystem(int system) {
309
                super.setReferenceSystem(system);
310
                for (int i = 0; layers != null && i < layers.length; i++) {
311
                        layers[i].setReferenceSystem(system);
312
                }
313
        }
314

    
315
        public void setAlpha(int alpha) {
316
                // first, get the biggest alpha in the layers and the index if such layer
317
                int maxAlpha = Integer.MIN_VALUE;
318
                int maxAlphaLayerIndex = 0;
319
                for (int i = 0; layers != null && i < layers.length; i++) {
320
                        if (layers[i].getColor().getAlpha() > maxAlpha) {
321
                                maxAlpha = layers[i].getColor().getAlpha();
322
                                maxAlphaLayerIndex = i;
323
                        }
324
                }
325

    
326
                // now, max alpha takes the value of the desired alpha and the rest
327
                // will take a scaled (to biggest alpha) alpha value
328
                for (int i = 0; layers != null && i < layers.length; i++) {
329
                        int r = layers[i].getColor().getRed();
330
                        int g = layers[i].getColor().getGreen();
331
                        int b = layers[i].getColor().getBlue();
332

    
333
                        if (i!=maxAlphaLayerIndex) {
334
                                double scaledAlpha = (double) layers[i].getColor().getAlpha()/maxAlpha;
335
                                int myAlpha = (int) (alpha*scaledAlpha);
336
                                if (myAlpha == 0) {
337
                                        myAlpha = 1;
338
                                }
339
                                layers[i].setColor(new Color(r, g, b, myAlpha));
340
                        } else {
341
                                int myAlpha = alpha;
342
                                if (myAlpha == 0) {
343
                                        myAlpha = 1;
344
                                }
345
                                layers[i].setColor(new Color(r, g, b, myAlpha));
346
                        }
347
                }
348

    
349
        }
350

    
351
        public Object clone() throws CloneNotSupportedException {
352
                MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
353

    
354
                // Clone layers
355
                if (layers != null) {
356
                        IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
357
                        for (int i = 0; i < layers.length; i++) {
358
                                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
359
                        }
360
                        copy.layers = layersCopy;
361
                }
362

    
363
                // Clone selection
364
                if (selectionSymbol != null) {
365
                        copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
366
                                        .clone();
367
                }
368

    
369
                return copy;
370
        }
371

    
372
        @SuppressWarnings("unchecked")
373
        public void loadFromState(PersistentState state)
374
                        throws PersistenceException {
375
                // Set parent fill symbol properties
376
                super.loadFromState(state);
377
                // Set own properties
378
                List layers = state.getList(FIELD_LAYERS);
379
                if (layers != null) {
380
                        for (int i = 0; i < layers.size(); i++) {
381
                                addLayer((ISymbol) layers.get(i));
382
                        }
383
                }
384
                setRotation(state.getDouble(FIELD_ROTATION));
385
        }
386

    
387
        public void saveToState(PersistentState state) throws PersistenceException {
388
                // Save parent fill symbol properties
389
                super.saveToState(state);
390
                // Save own properties
391
                if (layers != null && layers.length > 0) {
392
                        state.set(FIELD_LAYERS, Arrays.asList(layers));
393
                }
394
                state.set(FIELD_ROTATION, getRotation());
395
        }
396

    
397
        public static class RegisterPersistence implements Callable {
398

    
399
                public Object call() throws Exception {
400
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
401
                        if( manager.getDefinition(MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
402
                                DynStruct definition = manager.addDefinition(
403
                                                MultiLayerMarkerSymbol.class,
404
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME,
405
                                                MULTILAYER_MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
406
                                                null, 
407
                                                null
408
                                );
409
                                // Extend the MarkerSymbol base definition
410
                                definition.extend(manager.getDefinition(MARKER_SYMBOL_PERSISTENCE_DEFINITION_NAME));
411

    
412
                                // Layers
413
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IMarkerSymbol.class);
414
                                // Rotation
415
                                definition.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
416
                        }
417
                        return Boolean.TRUE;
418
                }
419
                
420
        }
421

    
422
        public static class RegisterSymbol implements Callable {
423

    
424
                public Object call() throws Exception {
425
                        int[] shapeTypes;
426
                        SymbolManager manager = MapContextLocator.getSymbolManager();
427

    
428
                shapeTypes =
429
                    new int[] { Geometry.TYPES.POINT, Geometry.TYPES.MULTIPOINT };
430
                manager.registerMultiLayerSymbol(IMarkerSymbol.SYMBOL_NAME,
431
                    shapeTypes,
432
                    MultiLayerMarkerSymbol.class);
433

    
434
                        return Boolean.TRUE;
435
                }
436
                
437
        }
438

    
439
}