Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2021 / extensions / org.gvsig.symbology / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / fill / impl / MultiLayerFillSymbol.java @ 34111

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

    
23
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl;
24

    
25
import java.awt.Color;
26
import java.awt.Graphics2D;
27
import java.awt.Rectangle;
28
import java.awt.geom.AffineTransform;
29
import java.util.ArrayList;
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.mapcontext.MapContext;
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.fill.IFillSymbol;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
44
import org.gvsig.tools.ToolsLocator;
45
import org.gvsig.tools.dynobject.DynStruct;
46
import org.gvsig.tools.persistence.PersistenceManager;
47
import org.gvsig.tools.persistence.PersistentState;
48
import org.gvsig.tools.persistence.exception.PersistenceException;
49
import org.gvsig.tools.task.Cancellable;
50
import org.gvsig.tools.util.Callable;
51
import org.slf4j.Logger;
52
import org.slf4j.LoggerFactory;
53

    
54

    
55
/**
56
 * MultiLayerFillSymbol is a symbol which allows to group several kind of fill symbols
57
 * (xxxFillSymbol implementing IFillSymbol)in one and treats it like single symbol.
58
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
59
 */
60
public class MultiLayerFillSymbol extends AbstractFillSymbol implements IFillSymbol, IMultiLayerSymbol{
61
        private static final Logger LOG = LoggerFactory.getLogger(MultiLayerFillSymbol.class);
62

    
63
    public static final String MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerFillSymbol";
64

    
65
    //    private static final String FIELD_SYMBOL_FOR_SELECTION = "symbolForSelection";
66
    private static final String FIELD_LAYERS = "layers";
67
    
68
        private static final double OPACITY_SELECTION_FACTOR = .8;
69
        private IFillSymbol[] layers = new IFillSymbol[0];
70
        private MultiLayerFillSymbol selectionSymbol;
71
//        private Object symbolType;
72

    
73
        public Color getFillColor() {
74
                /*
75
                 * a multilayer symbol does not define any color, the color
76
                 * of each layer is defined by the layer itself
77
                 */
78
                return null;
79
        }
80

    
81
        public int getOnePointRgb() {
82
                // will paint only the last layer pixel
83
                return layers[layers.length-1].getOnePointRgb();
84
        }
85

    
86
        public ILineSymbol getOutline() {
87
                /*
88
                 * a multilayer symbol does not define any outline, the outline
89
                 * of each layer is defined by the layer it self
90
                 */
91
                return null;
92
        }
93

    
94
        public boolean isSuitableFor(Geometry geom) {
95
                return geom.getType() == Geometry.TYPES.SURFACE;
96
        }
97

    
98
        public void setFillColor(Color color) {
99
                /*
100
                 * Will apply the color to each layer
101
                 */
102
                for (int i = 0; layers != null && i < layers.length; i++) {
103
                        layers[i].setFillColor(color);
104
                }
105
        }
106

    
107
        public void setOutline(ILineSymbol outline) {
108
                if (layers != null && layers.length > 0) {
109
                        for (int i = 0; i < layers.length - 1; i++) {
110
                                layers[i].setOutline(null);
111
                        }
112
                        layers[layers.length - 1].setOutline(outline);
113
                }
114
        }
115

    
116
        public void draw(Graphics2D g, AffineTransform affineTransform,
117
                        Geometry geom, Feature feature, Cancellable cancel) {
118
                for (int i = 0; (cancel == null || !cancel.isCanceled())
119
                                && layers != null && i < layers.length; i++) {
120
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
121
                }
122
        }
123

    
124
        public void drawInsideRectangle(Graphics2D g,
125
                        AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
126
                for (int i = 0; layers != null && i < layers.length; i++) {
127
                        layers[i].drawInsideRectangle(g, scaleInstance, r, properties);
128
                }
129
        }
130

    
131
        public void getPixExtentPlus(Geometry geom, float[] distances,
132
                        ViewPort viewPort, int dpi) {
133
                float[] myDistances = new float[] {0,0};
134
                distances[0] = 0;
135
                distances[1] = 0;
136
                for (int i = 0; layers != null && i < layers.length; i++) {
137
                        layers[i].getPixExtentPlus(geom, myDistances, viewPort, dpi);
138
                        distances[0] = Math.max(myDistances[0], distances[0]);
139
                        distances[1] = Math.max(myDistances[1], distances[1]);
140
                }
141
        }
142

    
143
        public ISymbol getSymbolForSelection() {
144
            // TODO: revisar
145
            
146
                if (selectionSymbol == null) {
147
                            MultiLayerFillSymbol selectionSymbol = 
148
                                new MultiLayerFillSymbol();
149
                        selectionSymbol.setDescription(getDescription());
150
//                        selectionSymbol.symbolType = symbolType;
151
                        for (int i = 0; layers != null && i < layers.length; i++) {
152
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
153
                        }
154
                        SimpleFillSymbol selLayer = new SimpleFillSymbol();
155
                        Color c = MapContext.getSelectionColor();
156
                        c = new Color(
157
                                        c.getRed(),
158
                                        c.getGreen(),
159
                                        c.getBlue(),
160
                                        (int) (255*OPACITY_SELECTION_FACTOR));
161
                        selLayer.setFillColor(c);
162
                        selLayer.setOutline(getOutline());
163
                        selectionSymbol.addLayer(selLayer);
164
                        setSymbolForSelection(selectionSymbol);
165
                }
166
                return selectionSymbol;
167

    
168
        }
169

    
170
        public int getSymbolType() {
171
                return Geometry.TYPES.SURFACE;
172
        }
173

    
174
        public void setPrintingProperties(PrintAttributes printProperties) {
175
                // TODO Implement it
176
                throw new Error("Not yet implemented!");
177

    
178
        }
179

    
180
        public String getClassName() {
181
                return getClass().getName();
182
        }
183

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

    
190
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
191
                layers[index] = (IFillSymbol) layer;
192
        }
193

    
194
        public void swapLayers(int index1, int index2) {
195
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
196
                layers[index2] = (IFillSymbol) aux1;
197
                layers[index1] = (IFillSymbol) aux2;
198
        }
199

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

    
208
        public int getLayerCount() {
209
                return layers.length;
210
        }
211

    
212
        public void addLayer(ISymbol newLayer) {
213
                addLayer(newLayer, layers.length);
214
        }
215

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

    
221
                selectionSymbol = null; /* forces the selection symbol to be re-created
222
                                                                  * next time it is required
223
                                                                  */
224
                if (layerIndex < 0 || layers.length < layerIndex) {
225
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
226
                }
227
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
228
                for (int i = 0; i < layers.length; i++) {
229
                        newLayers.add(layers[i]);
230
                }
231
                try {
232
                        newLayers.add(layerIndex, newLayer);
233
                        layers = (IFillSymbol[]) newLayers.toArray(new IFillSymbol[0]);
234
                } catch (ArrayStoreException asEx) {
235
                        throw new ClassCastException(newLayer.getClass().getName() + " is not an IFillSymbol");
236
                }
237
        }
238

    
239
        public boolean removeLayer(ISymbol layer) {
240

    
241
                int capacity = 0;
242
                capacity = layers.length;
243
                List<IFillSymbol> lst = new ArrayList<IFillSymbol>(capacity);
244
                for (int i = 0; layers != null && i < capacity; i++) {
245
                        lst.add(layers[i]);
246
                }
247
                boolean contains = lst.remove(layer);
248
                layers = (IFillSymbol[])lst.toArray(new IFillSymbol[0]);
249
                return contains;
250
        }
251
        
252
        public void setUnit(int unitIndex) {
253
                super.setUnit(unitIndex);
254
                for (int i = 0; layers != null && i < layers.length; i++) {
255
                        layers[i].setUnit(unitIndex);
256
                }
257
        }
258

    
259
        public void setReferenceSystem(int system) {
260
                super.setReferenceSystem(system);
261
                for (int i = 0; layers != null && i < layers.length; i++) {
262
                        layers[i].setReferenceSystem(system);
263
                }
264
        }
265

    
266
        /**
267
         *Returns the transparency of the multi layer fill symbol created
268
         */
269
        public int getFillAlpha() {
270
                // will compute the acumulated opacity
271
                double myAlpha = 0;
272
                for (int i = 0; layers != null && i < layers.length; i++) {
273
                        double layerAlpha = layers[i].getFillAlpha()/255D;
274
                        myAlpha += (1-myAlpha)*layerAlpha;
275
                }
276
                int result = (int) Math.round(myAlpha * 255);
277
                return (result>255) ? 255 : result;
278
        }
279

    
280

    
281
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
282
                double size = 0;
283
                for (int i = 0; layers != null && i < layers.length; i++) {
284
                        size = Math.max(size, layers[i].toCartographicSize(viewPort, dpi, geom));
285
                }
286
                return size;
287
        }
288
        
289
        public Object clone() throws CloneNotSupportedException {
290
                MultiLayerFillSymbol copy = (MultiLayerFillSymbol) super.clone();
291

    
292
                // Clone layers
293
                if (layers != null) {
294
                        IFillSymbol[] layersCopy = new IFillSymbol[layers.length];
295
                        for (int i = 0; i < layers.length; i++) {
296
                                layersCopy[i] = (IFillSymbol) layers[i].clone();
297
                        }
298
                        copy.layers = layersCopy;
299
                }
300

    
301
                // Clone selection
302
                if (selectionSymbol != null) {
303
                        copy.selectionSymbol = (MultiLayerFillSymbol) selectionSymbol
304
                                        .clone();
305
                }
306

    
307
                return copy;
308
        }
309

    
310
        private void setSymbolForSelection(MultiLayerFillSymbol symbolForSelection) {
311
                this.selectionSymbol = symbolForSelection;
312
        }
313

    
314
        @SuppressWarnings("unchecked")
315
        public void loadFromState(PersistentState state)
316
                        throws PersistenceException {
317
                // Set parent fill symbol properties
318
                super.loadFromState(state);
319
                LOG.warn("FIXME, fix implement of loadFromState");
320
                // Set own properties
321
                // setSymbolForSelection((MultiLayerFillSymbol)
322
                // state.get(FIELD_SYMBOL_FOR_SELECTION));
323
                List layers = state.getList(FIELD_LAYERS);
324
                if (layers != null) {
325
                        for (int i = 0; i < layers.size(); i++) {
326
                                addLayer((ISymbol) layers.get(i));
327
                        }
328
                }
329

    
330
        }
331

    
332
        public void saveToState(PersistentState state) throws PersistenceException {
333
                // Save parent fill symbol properties
334
                super.saveToState(state);
335
                LOG.warn("FIXME, fix implement of saveToState");
336
                // Save own properties
337

    
338
                // Don't use the getSymbolForSelection method, as it will create it
339
                // if it does not exist, and persistence will enter an infinite loop
340
                // state.set(FIELD_SYMBOL_FOR_SELECTION, selectionSymbol);
341
                state.set(FIELD_LAYERS, layers);
342
        }
343

    
344
        public static class RegisterPersistence implements Callable {
345

    
346
                public Object call() throws Exception {
347
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
348
                        if( manager.getDefinition(MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
349
                                DynStruct definition = manager.addDefinition(
350
                                                MultiLayerFillSymbol.class,
351
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
352
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
353
                                                null, 
354
                                                null
355
                                );
356

    
357
                                // Extend the FillSymbol base definition
358
                                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
359

    
360
                                // Selection Symbol
361
                                // definition.addDynFieldSingle(FIELD_SYMBOL_FOR_SELECTION).setType(
362
                                // DataTypes.OBJECT);
363

    
364
                                // Layers
365
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IFillSymbol.class);
366
                        }
367
                        return Boolean.TRUE;
368
                }
369
                
370
        }
371

    
372
        public static class RegisterSymbol implements Callable {
373

    
374
                public Object call() throws Exception {
375
                        int[] shapeTypes;
376
                        SymbolManager manager = MapContextLocator.getSymbolManager();
377

    
378
                        shapeTypes = new int[] { Geometry.TYPES.SURFACE,
379
                                        Geometry.TYPES.CIRCLE, Geometry.TYPES.ELLIPSE,
380
                                        Geometry.TYPES.MULTISURFACE };
381
                        manager.registerMultiLayerSymbol(IFillSymbol.SYMBOL_NAME,
382
                                        shapeTypes, MultiLayerFillSymbol.class);
383

    
384
                        return Boolean.TRUE;
385
                }
386
                
387
        }
388

    
389
}