Statistics
| Revision:

root / branches / v2_0_0_prep / extensions / org.gvsig.symbology / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / marker / impl / MultiLayerMarkerSymbol.java @ 31544

History | View | Annotate | Download (12.7 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.ViewPort;
37
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
38
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
40
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
41
import org.gvsig.tools.ToolsLocator;
42
import org.gvsig.tools.dynobject.DynClass;
43
import org.gvsig.tools.persistence.PersistenceException;
44
import org.gvsig.tools.persistence.PersistentState;
45
import org.gvsig.tools.task.Cancellable;
46
import org.gvsig.utils.XMLEntity;
47
import org.gvsig.utils.XMLException;
48

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

    
58
    public static final String MULTILAYER_MARKER_SYMBOL_DYNCLASS_NAME = "MultiLayerMarkerSymbol";
59
    
60
    private static final String FIELD_LAYERS = "layers";
61
    private static final String FIELD_ROTATION = "rotation";
62

    
63
    private IMarkerSymbol[] layers = new IMarkerSymbol[0];
64
        private MultiLayerMarkerSymbol selectionSymbol;
65
        private double markerSize;
66
        private double rotation;
67
        public Color getColor() {
68
                /*
69
                 * a multilayer symbol does not define any color, the color
70
                 * of each layer is defined by the layer itself
71
                 */
72
                return null;
73
        }
74

    
75
        public double getRotation() {
76
                return rotation;
77
        }
78

    
79
        public void setColor(Color color) {
80
                /*
81
                 * will apply the color to each layer
82
                 */
83
                for (int i = 0; layers != null && i < layers.length; i++) {
84
                        layers[i].setColor(color);
85
                }
86
        }
87

    
88
        public void setRotation(double rotation) {
89
                this.rotation = rotation;
90
        }
91

    
92
        public double getSize() {
93
                double myMarkerSize = 0;
94

    
95
                for (int i = 0; i < getLayerCount(); i++) {
96
                        myMarkerSize = Math.max(myMarkerSize, ((IMarkerSymbol) getLayer(i)).getSize());
97
                }
98

    
99
                if (markerSize != myMarkerSize) {
100
                        markerSize = myMarkerSize;
101
                }
102
                return markerSize;
103
        }
104

    
105
        public void setSize(double size) {
106
                if (size > 0 && size != getSize()) {
107

    
108
                        double scale = size / getSize();
109
                        this.markerSize = size;
110
                        for (int i = 0; layers != null && i < layers.length; i++) {
111
                                double lSize = layers[i].getSize();
112
                                layers[i].setSize(lSize*scale);
113
                        }
114
                }
115
        }
116

    
117

    
118

    
119
        public void draw(Graphics2D g, AffineTransform affineTransform,
120
                        Geometry geom, Feature feature, Cancellable cancel) {
121
                Point p = (Point) geom;
122
                g.rotate(rotation, p.getX(), p.getY());
123
                for (int i = 0; (cancel == null || !cancel.isCanceled())
124
                                && layers != null && i < layers.length; i++) {
125
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
126
                }
127
                g.rotate(-rotation, p.getX(), p.getY());
128
        }
129

    
130
        public void drawInsideRectangle(Graphics2D g, AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
131
                g.rotate(rotation, r.getCenterX(), r.getCenterY());
132
                for (int i = 0; layers != null && i < layers.length; i++) {
133
                        layers[i].drawInsideRectangle(g, scaleInstance, r, properties);
134
                }
135
                g.rotate(-rotation, r.getCenterX(), r.getCenterY());
136
        }
137

    
138
        public int getOnePointRgb() {
139
                // will paint only the last layer pixel
140
                return layers[layers.length-1].getOnePointRgb();
141
        }
142

    
143
        public void getPixExtentPlus(Geometry geom, float[] distances,
144
                        ViewPort viewPort, int dpi) {
145
                float[] myDistances = new float[] {0,0};
146
                distances[0] = 0;
147
                distances[1] = 0;
148
                for (int i = 0; layers != null && i < layers.length; i++) {
149
                        layers[i].getPixExtentPlus(geom, myDistances, viewPort, dpi);
150
                        distances[0] = Math.max(myDistances[0], distances[0]);
151
                        distances[1] = Math.max(myDistances[1], distances[1]);
152
                }
153
        }
154

    
155
        public ISymbol getSymbolForSelection() {
156
                if (selectionSymbol == null) {
157
                        selectionSymbol = new MultiLayerMarkerSymbol();
158
                        selectionSymbol.setDescription(getDescription());
159
                        for (int i = 0; layers != null && i < layers.length; i++) {
160
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
161
                        }
162
                }
163
                return selectionSymbol;
164

    
165
        }
166

    
167

    
168
        public XMLEntity getXMLEntity() throws XMLException {
169
                XMLEntity xml = new XMLEntity();
170

    
171
//                xml.putProperty("className", getClass().getName());
172
//                xml.putProperty("isShapeVisible", isShapeVisible());
173
//                xml.putProperty("desc", getDescription());
174
//                xml.putProperty("size",        getSize());
175
//                xml.putProperty("unit", getUnit());
176
//                xml.putProperty("referenceSystem", getReferenceSystem());
177
//                for (int i = 0; i < layers.length; i++) {
178
//                        xml.addChild(layers[i].getXMLEntity());
179
//                }
180
                return xml;
181
        }
182

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

    
187

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

    
192
        /**
193
         * TODO: replace with the new Persistence API
194
         */
195
        public void setXMLEntity(XMLEntity xml) {
196
//                setIsShapeVisible(xml.getBooleanProperty("isShapeVisible"));
197
//                setDescription(xml.getStringProperty("desc"));
198
//                setSize(xml.getDoubleProperty("size"));
199
//                setUnit(xml.getIntProperty("unit"));
200
//                setReferenceSystem(xml.getIntProperty("referenceSystem"));
201
//                for (int i = 0; i < xml.getChildrenCount(); i++) {
202
//                        addLayer(SymbologyFactory.createSymbolFromXML(xml.getChild(i), "layer" + i));
203
//                }
204
        }
205

    
206

    
207
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
208
                for (int i = 0; layers != null && i < layers.length; i++) {
209
                        layers[i].print(g, at, geom, properties);
210
                }
211

    
212
        }
213

    
214
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
215
                layers[index] = (IMarkerSymbol) layer;
216
        }
217

    
218
        public void swapLayers(int index1, int index2) {
219
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
220
                layers[index2] = (IMarkerSymbol) aux1;
221
                layers[index1] = (IMarkerSymbol) aux2;
222
        }
223

    
224
        public ISymbol getLayer(int layerIndex) {
225
//                try{
226
                        return layers[layerIndex];
227
//                } catch (Exception e) {
228
//                        return null;
229
//                }
230
        }
231

    
232
        public int getLayerCount() {
233
                return layers.length;
234
        }
235

    
236
        public void addLayer(ISymbol newLayer) {
237
                addLayer(newLayer, layers.length);
238
        }
239

    
240
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
241
                if (newLayer == null ) {
242
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
243
                }
244

    
245
                IMarkerSymbol newMarker = (IMarkerSymbol) newLayer;
246
                if (getLayerCount() == 0) {
247
                        // apply the new layer properties to this multilayer
248

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

    
279
        public boolean removeLayer(ISymbol layer) {
280

    
281
                int capacity = 0;
282
                capacity = layers.length;
283
                List<ISymbol> lst = new ArrayList<ISymbol>(capacity);
284
                for (int i = 0; i < capacity; i++) {
285
                        lst.add(layers[i]);
286
                }
287
                boolean contains = lst.remove(layer);
288
                layers = (IMarkerSymbol[])lst.toArray(new IMarkerSymbol[0]);
289
                return contains;
290
        }
291

    
292
        public void setUnit(int unit) {
293
                super.setUnit(unit);
294
                for (int i = 0; layers != null && i < layers.length; i++) {
295
                        layers[i].setUnit(unit);
296
                }
297
        }
298

    
299
        public void setReferenceSystem(int system) {
300
                super.setReferenceSystem(system);
301
                for (int i = 0; layers != null && i < layers.length; i++) {
302
                        layers[i].setReferenceSystem(system);
303
                }
304
        }
305

    
306
        public void setAlpha(int alpha) {
307
                // first, get the biggest alpha in the layers and the index if such layer
308
                int maxAlpha = Integer.MIN_VALUE;
309
                int maxAlphaLayerIndex = 0;
310
                for (int i = 0; layers != null && i < layers.length; i++) {
311
                        if (layers[i].getColor().getAlpha() > maxAlpha) {
312
                                maxAlpha = layers[i].getColor().getAlpha();
313
                                maxAlphaLayerIndex = i;
314
                        }
315
                }
316

    
317
                // now, max alpha takes the value of the desired alpha and the rest
318
                // will take a scaled (to biggest alpha) alpha value
319
                for (int i = 0; layers != null && i < layers.length; i++) {
320
                        int r = layers[i].getColor().getRed();
321
                        int g = layers[i].getColor().getGreen();
322
                        int b = layers[i].getColor().getBlue();
323

    
324
                        if (i!=maxAlphaLayerIndex) {
325
                                double scaledAlpha = (double) layers[i].getColor().getAlpha()/maxAlpha;
326
                                int myAlpha = (int) (alpha*scaledAlpha);
327
                                if (myAlpha == 0) {
328
                                        myAlpha = 1;
329
                                }
330
                                layers[i].setColor(new Color(r, g, b, myAlpha));
331
                        } else {
332
                                int myAlpha = alpha;
333
                                if (myAlpha == 0) {
334
                                        myAlpha = 1;
335
                                }
336
                                layers[i].setColor(new Color(r, g, b, myAlpha));
337
                        }
338
                }
339

    
340
        }
341

    
342
        public Object clone() throws CloneNotSupportedException {
343
                MultiLayerMarkerSymbol copy = (MultiLayerMarkerSymbol) super.clone();
344

    
345
                // Clone layers
346
                if (layers != null) {
347
                        IMarkerSymbol[] layersCopy = new IMarkerSymbol[layers.length];
348
                        for (int i = 0; i < layers.length; i++) {
349
                                layersCopy[i] = (IMarkerSymbol) layers[i].clone();
350
                        }
351
                        copy.layers = layersCopy;
352
                }
353

    
354
                // Clone selection
355
                if (selectionSymbol != null) {
356
                        copy.selectionSymbol = (MultiLayerMarkerSymbol) selectionSymbol
357
                                        .clone();
358
                }
359

    
360
                return copy;
361
        }
362

    
363
        @SuppressWarnings("unchecked")
364
        public void loadFromState(PersistentState state)
365
                        throws PersistenceException {
366
                // Set parent fill symbol properties
367
                super.loadFromState(state);
368
                // Set own properties
369
                List layers = state.getList(FIELD_LAYERS);
370
                if (layers != null) {
371
                        for (int i = 0; i < layers.size(); i++) {
372
                                addLayer((ISymbol) layers.get(i));
373
                        }
374
                }
375
                setRotation(state.getDouble(FIELD_ROTATION));
376
        }
377

    
378
        public void saveToState(PersistentState state) throws PersistenceException {
379
                // Save parent fill symbol properties
380
                super.saveToState(state);
381
                // Save own properties
382
                if (layers != null && layers.length > 0) {
383
                        state.set(FIELD_LAYERS, Arrays.asList(layers));
384
                }
385
                state.set(FIELD_ROTATION, getRotation());
386
        }
387

    
388
        public static void registerPersistence() {
389
                // Add the MultiLayerMarkerSymbol DynClass definition.
390
                DynClass dynClass = ToolsLocator.getDynObjectManager().add(
391
                                MULTILAYER_MARKER_SYMBOL_DYNCLASS_NAME);
392

    
393
                // Extend the MarkerSymbol base definition
394
                dynClass.extend(MARKER_SYMBOL_DYNCLASS_NAME);
395

    
396
                // Layers
397
                dynClass.addDynFieldList(FIELD_LAYERS);
398
                // Rotation
399
                dynClass.addDynFieldDouble(FIELD_ROTATION).setMandatory(true);
400

    
401
                // Register in persistence
402
                ToolsLocator.getPersistenceManager().registerClass(
403
                                MultiLayerMarkerSymbol.class, dynClass);
404
        }
405

    
406
}