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 / fill / impl / MultiLayerFillSymbol.java @ 47476

History | View | Annotate | Download (12.4 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.fill.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
import org.gvsig.fmap.dal.feature.Feature;
34
import org.gvsig.fmap.geom.Geometry;
35
import org.gvsig.fmap.geom.type.GeometryType;
36
import org.gvsig.fmap.mapcontext.MapContextLocator;
37
import org.gvsig.fmap.mapcontext.ViewPort;
38
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
40
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
41
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol_v2;
42
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IFillSymbol;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IMultiLayerFillSymbol;
45
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
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
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

    
56

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

    
65
    public static final String MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerFillSymbol";
66

    
67
    private static final String FIELD_LAYERS = "layers";
68

    
69
        private static final double OPACITY_SELECTION_FACTOR = .8;
70
        private IFillSymbol[] layers = new IFillSymbol[0];
71
        private MultiLayerFillSymbol selectionSymbol;
72
    private double[] sizes;
73
        
74
        @Override
75
        public Color getFillColor() {
76
                /*
77
                 * a multilayer symbol does not define any color, the color
78
                 * of each layer is defined by the layer itself
79
                 */
80
                return null;
81
        }
82

    
83
//        @Override
84
//        public int getOnePointRgb() {
85
//                // will paint only the last layer pixel
86
//                return layers[layers.length-1].getOnePointRgb();
87
//        }
88

    
89
        @Override
90
        public ILineSymbol getOutline() {
91
                /*
92
                 * a multilayer symbol does not define any outline, the outline
93
                 * of each layer is defined by the layer it self
94
                 */
95
                return null;
96
        }
97

    
98
    @Override
99
        public boolean isSuitableFor(Geometry geom) {
100
        GeometryType gt = geom.getGeometryType();
101
        return gt.isTypeOf(Geometry.TYPES.SURFACE);
102
        }
103

    
104
    @Override
105
        public void setFillColor(Color color) {
106
                /*
107
                 * Will apply the color to each layer
108
                 */
109
                for (int i = 0; layers != null && i < layers.length; i++) {
110
                        layers[i].setFillColor(color);
111
                }
112
        }
113

    
114
        @Override
115
        public void setOutline(ILineSymbol outline) {
116
                if (layers != null && layers.length > 0) {
117
                        for (int i = 0; i < layers.length - 1; i++) {
118
                                layers[i].setOutline(null);
119
                        }
120
                        layers[layers.length - 1].setOutline(outline);
121
                }
122
        }
123

    
124
    @Override
125
    public void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Feature f, Cancellable cancel, Rectangle r) {
126
        for (int i = 0; (cancel == null || !cancel.isCanceled())
127
                && layers != null && i < layers.length; i++) {
128
            ISymbol layer = layers[i];
129
            if (layer == null) {
130
                continue;
131
            }
132
            if(layer instanceof CartographicSupport){
133
                ((CartographicSupport)layer).setCartographicContext(this.getCartographicContext());
134
            }
135
            if(layer instanceof ISymbol_v2){
136
                ((ISymbol_v2)layer).draw(g, affineTransform, geom, f, cancel, r);
137
            } else {
138
                layer.draw(g, affineTransform, geom, f, cancel);
139
            }
140
        }
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
        @Override
156
        public ISymbol getSymbolForSelection() {
157
        if (selectionSymbol == null) {
158
                            MultiLayerFillSymbol selectionSymbol =
159
                                new MultiLayerFillSymbol();
160
                        selectionSymbol.setDescription(getDescription());
161
                        for (int i = 0; layers != null && i < layers.length; i++) {
162
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
163
                        }
164
                        setSymbolForSelection(selectionSymbol);
165
                } else {
166
          for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
167
                selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
168
            }
169
        }
170
        if (selectionSymbol instanceof CartographicSupport) {
171
            ((CartographicSupport) selectionSymbol).setUnit(this.getUnit());
172
        }
173
        
174
                return selectionSymbol;
175

    
176
        }
177

    
178
        @Override
179
        public int getSymbolType() {
180
                return Geometry.TYPES.SURFACE;
181
        }
182

    
183
        @Override
184
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
185
                layers[index] = (IFillSymbol) layer;
186
        }
187

    
188
        @Override
189
        public void swapLayers(int index1, int index2) {
190
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
191
                layers[index2] = (IFillSymbol) aux1;
192
                layers[index1] = (IFillSymbol) aux2;
193
        }
194

    
195
        @Override
196
        public ISymbol getLayer(int layerIndex) {
197
            return layers[layerIndex];
198
        }
199

    
200
        @Override
201
        public int getLayerCount() {
202
                return layers.length;
203
        }
204

    
205
        @Override
206
        public void addLayer(ISymbol newLayer) {
207
                addLayer(newLayer, layers.length);
208
        }
209

    
210
        @Override
211
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
212
                if (newLayer == null ) {
213
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
214
                }
215

    
216
                selectionSymbol = null; /* forces the selection symbol to be re-created
217
                                                                  * next time it is required
218
                                                                  */
219
                if (layerIndex < 0 || layers.length < layerIndex) {
220
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
221
                }
222
                List<ISymbol> newLayers = new ArrayList<>();
223
                newLayers.addAll(Arrays.asList(layers));
224
                try {
225
                        newLayers.add(layerIndex, newLayer);
226
                        layers = (IFillSymbol[]) newLayers.toArray(new IFillSymbol[0]);
227
                } catch (ArrayStoreException asEx) {
228
                        throw new ClassCastException(newLayer.getClass().getName() + " is not an IFillSymbol");
229
                }
230
        }
231

    
232
        @Override
233
        public boolean removeLayer(ISymbol layer) {
234

    
235
                int capacity = layers.length;
236
                List<IFillSymbol> lst = new ArrayList<IFillSymbol>(capacity);
237
                for (int i = 0; layers != null && i < capacity; i++) {
238
                        lst.add(layers[i]);
239
                }
240
                boolean contains = lst.remove(layer);
241
                layers = (IFillSymbol[])lst.toArray(new IFillSymbol[0]);
242
                return contains;
243
        }
244

    
245
        @Override
246
        public void setUnit(int unitIndex) {
247
                super.setUnit(unitIndex);
248
                for (int i = 0; layers != null && i < layers.length; i++) {
249
                        layers[i].setUnit(unitIndex);
250
                }
251
        }
252

    
253
        @Override
254
        public void setReferenceSystem(int system) {
255
                super.setReferenceSystem(system);
256
                for (int i = 0; layers != null && i < layers.length; i++) {
257
                        layers[i].setReferenceSystem(system);
258
                }
259
        }
260

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

    
276
        public Object clone() throws CloneNotSupportedException {
277
                MultiLayerFillSymbol copy = (MultiLayerFillSymbol) super.clone();
278

    
279
                // Clone layers
280
                if (layers != null) {
281
                        IFillSymbol[] layersCopy = new IFillSymbol[layers.length];
282
                        for (int i = 0; i < layers.length; i++) {
283
                                layersCopy[i] = (IFillSymbol) layers[i].clone();
284
                        }
285
                        copy.layers = layersCopy;
286
                }
287

    
288
                // Clone selection
289
                if (selectionSymbol != null) {
290
                        copy.selectionSymbol = (MultiLayerFillSymbol) selectionSymbol
291
                                        .clone();
292
                }
293

    
294
                return copy;
295
        }
296

    
297
        private void setSymbolForSelection(MultiLayerFillSymbol symbolForSelection) {
298
                this.selectionSymbol = symbolForSelection;
299
        }
300

    
301
        @SuppressWarnings("unchecked")
302
        @Override
303
        public void loadFromState(PersistentState state)
304
                        throws PersistenceException {
305
                // Set parent fill symbol properties
306
                super.loadFromState(state);
307
                LOG.warn("FIXME, fix implement of loadFromState");
308
                // Set own properties
309
                // setSymbolForSelection((MultiLayerFillSymbol)
310
                // state.get(FIELD_SYMBOL_FOR_SELECTION));
311
                List theLayers = state.getList(FIELD_LAYERS);
312
                if (theLayers != null) {
313
                        for (int i = 0; i < theLayers.size(); i++) {
314
                                addLayer((ISymbol) theLayers.get(i));
315
                        }
316
                }
317

    
318
        }
319

    
320
        @Override
321
        public void saveToState(PersistentState state) throws PersistenceException {
322
                // Save parent fill symbol properties
323
                super.saveToState(state);
324
                LOG.warn("FIXME, fix implement of saveToState");
325
                // Save own properties
326

    
327
                // Don't use the getSymbolForSelection method, as it will create it
328
                // if it does not exist, and persistence will enter an infinite loop
329
                // state.set(FIELD_SYMBOL_FOR_SELECTION, selectionSymbol);
330
                state.set(FIELD_LAYERS, layers);
331
        }
332

    
333
        public static class RegisterPersistence implements Callable {
334

    
335
                @Override
336
                public Object call() throws Exception {
337
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
338
                        if( manager.getDefinition(MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
339
                                DynStruct definition = manager.addDefinition(
340
                                                MultiLayerFillSymbol.class,
341
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
342
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
343
                                                null,
344
                                                null
345
                                );
346

    
347
                                // Extend the FillSymbol base definition
348
                                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
349

    
350
                                // Selection Symbol
351
                                // definition.addDynFieldSingle(FIELD_SYMBOL_FOR_SELECTION).setType(
352
                                // DataTypes.OBJECT);
353

    
354
                                // Layers
355
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IFillSymbol.class);
356
                        }
357
                        return Boolean.TRUE;
358
                }
359

    
360
        }
361

    
362
        public static class RegisterSymbol implements Callable {
363

    
364
                @Override
365
                public Object call() throws Exception {
366
                        int[] shapeTypes;
367
                        SymbolManager manager = MapContextLocator.getSymbolManager();
368

    
369
                        shapeTypes = new int[] { Geometry.TYPES.SURFACE,
370
                                        Geometry.TYPES.MULTISURFACE };
371
                        manager.registerMultiLayerSymbol(IFillSymbol.SYMBOL_NAME,
372
                                        shapeTypes, MultiLayerFillSymbol.class);
373

    
374
                        return Boolean.TRUE;
375
                }
376

    
377
        }
378

    
379
}