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

History | View | Annotate | Download (13.1 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.List;
32

    
33
import org.gvsig.compat.print.PrintAttributes;
34
import org.gvsig.fmap.dal.feature.Feature;
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.type.GeometryType;
37
import org.gvsig.fmap.mapcontext.MapContext;
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.fill.IFillSymbol;
45
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IMultiLayerFillSymbol;
46
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
47
import org.gvsig.tools.ToolsLocator;
48
import org.gvsig.tools.dynobject.DynStruct;
49
import org.gvsig.tools.persistence.PersistenceManager;
50
import org.gvsig.tools.persistence.PersistentState;
51
import org.gvsig.tools.persistence.exception.PersistenceException;
52
import org.gvsig.tools.task.Cancellable;
53
import org.gvsig.tools.util.Callable;
54
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
56

    
57

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

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

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

    
70
        private static final double OPACITY_SELECTION_FACTOR = .8;
71
        private IFillSymbol[] layers = new IFillSymbol[0];
72
        private MultiLayerFillSymbol selectionSymbol;
73

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

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

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

    
95
    @Override
96
        public boolean isSuitableFor(Geometry geom) {
97
        GeometryType gt = geom.getGeometryType();
98
        if( gt.isTypeOf(Geometry.TYPES.SURFACE) ) {
99
            return true;
100
        }
101
        return false;
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
        public void setOutline(ILineSymbol outline) {
115
                if (layers != null && layers.length > 0) {
116
                        for (int i = 0; i < layers.length - 1; i++) {
117
                                layers[i].setOutline(null);
118
                        }
119
                        layers[layers.length - 1].setOutline(outline);
120
                }
121
        }
122

    
123
        public void draw(Graphics2D g, AffineTransform affineTransform,
124
                        Geometry geom, Feature feature, Cancellable cancel) {
125
                for (int i = 0; (cancel == null || !cancel.isCanceled())
126
                                && layers != null && i < layers.length; i++) {
127
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
128
                }
129
        }
130

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

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

    
150
        public ISymbol getSymbolForSelection() {
151
            // TODO: revisar
152
        Color c = MapContext.getSelectionColor();
153
        c = new Color(
154
                c.getRed(),
155
                c.getGreen(),
156
                c.getBlue(),
157
                (int) (c.getAlpha()));//*OPACITY_SELECTION_FACTOR));
158
        if (selectionSymbol == null) {
159
                            MultiLayerFillSymbol selectionSymbol =
160
                                new MultiLayerFillSymbol();
161
                        selectionSymbol.setDescription(getDescription());
162
                        for (int i = 0; layers != null && i < layers.length; i++) {
163
                                selectionSymbol.addLayer(layers[i].getSymbolForSelection());
164
                        }
165
//                        SimpleFillSymbol selLayer = new SimpleFillSymbol();
166
//
167
//                        selLayer.setFillColor(c);
168
//                        selLayer.setOutline(getOutline());
169
//                        selectionSymbol.addLayer(selLayer);
170
                        setSymbolForSelection(selectionSymbol);
171
                } else {
172
          for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
173
                selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
174
//                if (i==selectionSymbol.getLayerCount()-1){
175
//                    ((SimpleFillSymbol)selectionSymbol.getLayer(i)).setFillColor(c);
176
//                }
177
            }
178
        }
179
                return selectionSymbol;
180

    
181
        }
182

    
183
        public int getSymbolType() {
184
                return Geometry.TYPES.SURFACE;
185
        }
186

    
187
//        public void setPrintingProperties(PrintAttributes printProperties) {
188
//                // TODO Implement it
189
//                throw new Error("Not yet implemented!");
190
//
191
//        }
192

    
193
//        public String getClassName() {
194
//                return getClass().getName();
195
//        }
196

    
197
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
198
                for (int i = 0; layers != null && i < layers.length; i++) {
199
                        layers[i].print(g, at, geom, properties);
200
                }
201
        }
202

    
203
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
204
                layers[index] = (IFillSymbol) layer;
205
        }
206

    
207
        public void swapLayers(int index1, int index2) {
208
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
209
                layers[index2] = (IFillSymbol) aux1;
210
                layers[index1] = (IFillSymbol) aux2;
211
        }
212

    
213
        public ISymbol getLayer(int layerIndex) {
214
//                try{
215
                        return layers[layerIndex];
216
//                } catch (Exception e) {
217
//                        return null;
218
//                }
219
        }
220

    
221
        public int getLayerCount() {
222
                return layers.length;
223
        }
224

    
225
        public void addLayer(ISymbol newLayer) {
226
                addLayer(newLayer, layers.length);
227
        }
228

    
229
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
230
                if (newLayer == null ) {
231
                        /*|| newLayer instanceof ILabelStyle)*/ return; // null or symbols that are styles are not allowed
232
                }
233

    
234
                selectionSymbol = null; /* forces the selection symbol to be re-created
235
                                                                  * next time it is required
236
                                                                  */
237
                if (layerIndex < 0 || layers.length < layerIndex) {
238
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
239
                }
240
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
241
                for (int i = 0; i < layers.length; i++) {
242
                        newLayers.add(layers[i]);
243
                }
244
                try {
245
                        newLayers.add(layerIndex, newLayer);
246
                        layers = (IFillSymbol[]) newLayers.toArray(new IFillSymbol[0]);
247
                } catch (ArrayStoreException asEx) {
248
                        throw new ClassCastException(newLayer.getClass().getName() + " is not an IFillSymbol");
249
                }
250
        }
251

    
252
        public boolean removeLayer(ISymbol layer) {
253

    
254
                int capacity = 0;
255
                capacity = layers.length;
256
                List<IFillSymbol> lst = new ArrayList<IFillSymbol>(capacity);
257
                for (int i = 0; layers != null && i < capacity; i++) {
258
                        lst.add(layers[i]);
259
                }
260
                boolean contains = lst.remove(layer);
261
                layers = (IFillSymbol[])lst.toArray(new IFillSymbol[0]);
262
                return contains;
263
        }
264

    
265
        public void setUnit(int unitIndex) {
266
                super.setUnit(unitIndex);
267
                for (int i = 0; layers != null && i < layers.length; i++) {
268
                        layers[i].setUnit(unitIndex);
269
                }
270
        }
271

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

    
279
        /**
280
         *Returns the transparency of the multi layer fill symbol created
281
         */
282
        public int getFillAlpha() {
283
                // will compute the acumulated opacity
284
                double myAlpha = 0;
285
                for (int i = 0; layers != null && i < layers.length; i++) {
286
                        double layerAlpha = layers[i].getFillAlpha()/255D;
287
                        myAlpha += (1-myAlpha)*layerAlpha;
288
                }
289
                int result = (int) Math.round(myAlpha * 255);
290
                return (result>255) ? 255 : result;
291
        }
292

    
293

    
294
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
295
                double size = 0;
296
                for (int i = 0; layers != null && i < layers.length; i++) {
297
                        size = Math.max(size, layers[i].toCartographicSize(viewPort, dpi, geom));
298
                }
299
                return size;
300
        }
301

    
302
        public Object clone() throws CloneNotSupportedException {
303
                MultiLayerFillSymbol copy = (MultiLayerFillSymbol) super.clone();
304

    
305
                // Clone layers
306
                if (layers != null) {
307
                        IFillSymbol[] layersCopy = new IFillSymbol[layers.length];
308
                        for (int i = 0; i < layers.length; i++) {
309
                                layersCopy[i] = (IFillSymbol) layers[i].clone();
310
                        }
311
                        copy.layers = layersCopy;
312
                }
313

    
314
                // Clone selection
315
                if (selectionSymbol != null) {
316
                        copy.selectionSymbol = (MultiLayerFillSymbol) selectionSymbol
317
                                        .clone();
318
                }
319

    
320
                return copy;
321
        }
322

    
323
        private void setSymbolForSelection(MultiLayerFillSymbol symbolForSelection) {
324
                this.selectionSymbol = symbolForSelection;
325
        }
326

    
327
        @SuppressWarnings("unchecked")
328
        public void loadFromState(PersistentState state)
329
                        throws PersistenceException {
330
                // Set parent fill symbol properties
331
                super.loadFromState(state);
332
                LOG.warn("FIXME, fix implement of loadFromState");
333
                // Set own properties
334
                // setSymbolForSelection((MultiLayerFillSymbol)
335
                // state.get(FIELD_SYMBOL_FOR_SELECTION));
336
                List layers = state.getList(FIELD_LAYERS);
337
                if (layers != null) {
338
                        for (int i = 0; i < layers.size(); i++) {
339
                                addLayer((ISymbol) layers.get(i));
340
                        }
341
                }
342

    
343
        }
344

    
345
        public void saveToState(PersistentState state) throws PersistenceException {
346
                // Save parent fill symbol properties
347
                super.saveToState(state);
348
                LOG.warn("FIXME, fix implement of saveToState");
349
                // Save own properties
350

    
351
                // Don't use the getSymbolForSelection method, as it will create it
352
                // if it does not exist, and persistence will enter an infinite loop
353
                // state.set(FIELD_SYMBOL_FOR_SELECTION, selectionSymbol);
354
                state.set(FIELD_LAYERS, layers);
355
        }
356

    
357
        public static class RegisterPersistence implements Callable {
358

    
359
                public Object call() throws Exception {
360
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
361
                        if( manager.getDefinition(MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
362
                                DynStruct definition = manager.addDefinition(
363
                                                MultiLayerFillSymbol.class,
364
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
365
                                                MULTILAYER_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
366
                                                null,
367
                                                null
368
                                );
369

    
370
                                // Extend the FillSymbol base definition
371
                                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
372

    
373
                                // Selection Symbol
374
                                // definition.addDynFieldSingle(FIELD_SYMBOL_FOR_SELECTION).setType(
375
                                // DataTypes.OBJECT);
376

    
377
                                // Layers
378
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(IFillSymbol.class);
379
                        }
380
                        return Boolean.TRUE;
381
                }
382

    
383
        }
384

    
385
        public static class RegisterSymbol implements Callable {
386

    
387
                public Object call() throws Exception {
388
                        int[] shapeTypes;
389
                        SymbolManager manager = MapContextLocator.getSymbolManager();
390

    
391
                        shapeTypes = new int[] { Geometry.TYPES.SURFACE,
392
                                        Geometry.TYPES.MULTISURFACE };
393
                        manager.registerMultiLayerSymbol(IFillSymbol.SYMBOL_NAME,
394
                                        shapeTypes, MultiLayerFillSymbol.class);
395

    
396
                        return Boolean.TRUE;
397
                }
398

    
399
        }
400

    
401
}