Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / line / impl / MultiLayerLineSymbol.java @ 34294

History | View | Annotate | Download (12.3 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.line.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.List;
30

    
31
import org.gvsig.compat.print.PrintAttributes;
32
import org.gvsig.fmap.dal.feature.Feature;
33
import org.gvsig.fmap.geom.Geometry;
34
import org.gvsig.fmap.mapcontext.MapContextLocator;
35
import org.gvsig.fmap.mapcontext.ViewPort;
36
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
37
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
38
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
40
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
41
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.IMultiLayerLineSymbol;
42
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.ILineStyle;
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

    
51
/**
52
 * MultiLayerLineSymbol allows to create new symbols using a composition of several lineal
53
 * symbols (xxxLineSymbol implementing ILineSymbol)and be treated as an only one symbol.
54
 *
55
 * @author  jaume dominguez faus - jaume.dominguez@iver.es
56
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
57
 */
58
public class MultiLayerLineSymbol extends AbstractLineSymbol implements
59
                ILineSymbol, IMultiLayerSymbol, IMultiLayerLineSymbol {
60

    
61
    public static final String MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME = "MultiLayerLineSymbol";
62
    
63
    private static final String FIELD_LAYERS = "layers";
64
    
65
    private ILineSymbol[] layers = new ILineSymbol[0];
66
        private MultiLayerLineSymbol selectionSymbol;
67
        
68
        // Cached greatest line width from all the layers
69
        private double lineWidth;
70

    
71
        public MultiLayerLineSymbol() {
72
                super();
73
        }
74
        
75
        public Color getColor() {
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
        public ILineStyle getLineStyle() {
84
                /*
85
                 * a multilayer symbol does not define any style, the style
86
                 * of each layer is defined by the layer itself
87
                 */
88
                return null;
89
        }
90

    
91
    public double getLineWidth() {
92
        return lineWidth;
93
    }
94

    
95
//    private double calculateLineWidth() {
96
//        double myLineWidth = 0;
97
//        for (int i = 0; i < getLayerCount(); i++) {
98
//            myLineWidth = Math.max(myLineWidth,
99
//                    ((ILineSymbol) getLayer(i)).getLineWidth());
100
//        }
101
//        return myLineWidth;
102
//    }
103

    
104
    public void setLineWidth(double width) {        
105
        if (width > 0 && width != lineWidth) {
106
            this.lineWidth = width;
107
            double scaleFactor = width / lineWidth;
108
                        for (int i = 0; layers != null && i < layers.length; i++) {
109
                layers[i].setLineWidth(layers[i].getLineWidth() * scaleFactor);
110
            }
111
        }
112
    }
113

    
114
        public void setLineColor(Color color) {
115
                /*
116
                 * will apply the color to each layer
117
                 */
118
                for (int i = 0; layers != null && i < layers.length; i++) {
119
                        layers[i].setLineColor(color);
120
                }
121
        }
122

    
123
        public void setLineStyle(ILineStyle lineStyle) {
124
                /*
125
                 * will apply the same patter to each layer
126
                 */
127
                for (int i = 0; layers != null && i < layers.length; i++) {
128
                        layers[i].setLineStyle(lineStyle);
129
                }
130
        }
131

    
132
        public void draw(Graphics2D g, AffineTransform affineTransform,
133
                        Geometry geom, Feature feature, Cancellable cancel) {
134
                for (int i = 0; (cancel == null || !cancel.isCanceled())
135
                                && layers != null && i < layers.length; i++) {
136
                        layers[i].draw(g, affineTransform, geom, feature, cancel);
137
                }
138
        }
139

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

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

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

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

    
174
        public boolean isSuitableFor(Geometry geom) {
175
                return geom.getType() == Geometry.TYPES.CURVE;
176
        }
177

    
178
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
179
                for (int i = 0; layers != null && i < layers.length; i++) {
180
                        layers[i].print(g, at, geom, properties);
181
                }
182

    
183
        }
184

    
185
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
186
                layers[index] = (ILineSymbol) layer;
187
        }
188

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

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

    
199
        public int getLayerCount() {
200
                return layers.length;
201
        }
202

    
203
        public void addLayer(ISymbol newLayer) {
204
                addLayer(newLayer, layers.length);
205
        }
206

    
207
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
208

    
209
                if (newLayer == null) {
210
                        return; // null are not allowed
211
                }
212
                ILineSymbol newLine = (ILineSymbol) newLayer;
213
                if (getLayerCount() == 0) {
214
                        // apply the new layer properties to this multilayer
215

    
216
                        setReferenceSystem(newLine.getReferenceSystem());
217
                        setUnit(newLine.getUnit());
218
                        lineWidth = newLine.getLineWidth();
219
                } else {
220
                        if (newLine.getLineWidth() > getLineWidth()) {
221
                                lineWidth = newLine.getLineWidth();
222
                        }
223
                        newLine.setReferenceSystem(getReferenceSystem());
224
                        newLine.setUnit(getUnit());
225
                }
226

    
227
                selectionSymbol = null; /* forces the selection symbol to be re-created
228
                                                                  * next time it is required
229
                                                                  */
230

    
231

    
232
                if (layerIndex < 0 || layers.length < layerIndex) {
233
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
234
                }
235
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
236
                for (int i = 0; i < layers.length; i++) {
237
                        newLayers.add(layers[i]);
238
                }
239
                try {
240
                        newLayers.add(layerIndex, newLayer);
241
                        layers = (ILineSymbol[])newLayers.toArray(new ILineSymbol[0]);
242
                } catch (ArrayStoreException asEx) {
243
                        throw new ClassCastException(newLayer.getClass().getName()+" is not an ILineSymbol");
244
                }
245
        }
246

    
247
        public boolean removeLayer(ISymbol layer) {
248

    
249
                int capacity = 0;
250
                capacity = layers.length;
251
                List<ILineSymbol> lst = new ArrayList<ILineSymbol>(capacity);
252
                for (int i = 0; i < capacity; i++) {
253
                        lst.add(layers[i]);
254
                }
255
                boolean contains = lst.remove(layer);
256
                layers = (ILineSymbol[])lst.toArray(new ILineSymbol[0]);
257
                return contains;
258
        }
259

    
260
        public int getAlpha() {
261
                // will compute the acumulated opacity
262
                double myAlpha = 0;
263
                for (int i = 0; i < layers.length; i++) {
264
                        double layerAlpha = layers[i].getAlpha()/255D;
265
                        myAlpha += (1-myAlpha)*layerAlpha;
266
                }
267
                int result = (int) Math.round(myAlpha * 255);
268
                return (result>255) ? 255 : result;
269
        }
270

    
271
        public void setAlpha(int outlineAlpha) {
272
                // first, get the biggest alpha in the layers and the index if such layer
273
                int maxAlpha = Integer.MIN_VALUE;
274
                int maxAlphaLayerIndex = 0;
275
                for (int i = 0; i < layers.length; i++) {
276
                        if (layers[i].getAlpha() > maxAlpha) {
277
                                maxAlpha = layers[i].getAlpha();
278
                                maxAlphaLayerIndex = i;
279
                        }
280
                }
281

    
282
                // now, max alpha takes the value of the desired alpha and the rest
283
                // will take a scaled (to biggest alpha) alpha value
284
                for (int i = 0; layers != null && i < layers.length; i++) {
285
                        if (i!=maxAlphaLayerIndex) {
286
                                double scaledAlpha = (double) layers[i].getAlpha()/maxAlpha;
287
                                int myAlpha = (int) (outlineAlpha*scaledAlpha);
288
                                if (myAlpha == 0) {
289
                                        myAlpha = 1;
290
                                }
291
                                layers[i].setAlpha(myAlpha);
292
                        } else {
293
                                int myAlpha = outlineAlpha;
294
                                if (myAlpha == 0) {
295
                                        myAlpha = 1;
296
                                }
297
                                layers[i].setAlpha(myAlpha);
298
                        }
299
                }
300

    
301
        }
302

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

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

    
317
        public void setCartographicSize(double cartographicSize, Geometry geom) {
318
//                super.setCartographicSize(cartographicSize, shp);
319
                setLineWidth(cartographicSize);
320
        }
321

    
322
        public Object clone() throws CloneNotSupportedException {
323
                MultiLayerLineSymbol copy = (MultiLayerLineSymbol) super.clone();
324

    
325
                // Clone layers
326
                if (layers != null && layers.length > 0) {
327
                        ILineSymbol[] layersCopy = new ILineSymbol[layers.length];
328
                        for (int i = 0; i < layers.length; i++) {
329
                                layersCopy[i] = (ILineSymbol) layers[i].clone();
330
                        }
331
                        copy.layers = layersCopy;
332
                }
333

    
334
                // Clone selection
335
                if (selectionSymbol != null) {
336
                        copy.selectionSymbol = (MultiLayerLineSymbol) selectionSymbol
337
                                        .clone();
338
                }
339

    
340
                return copy;
341
        }
342

    
343
        @SuppressWarnings("unchecked")
344
        public void loadFromState(PersistentState state)
345
                        throws PersistenceException {
346
                // Set parent fill symbol properties
347
                super.loadFromState(state);
348
                // Set own properties
349
                List layers = state.getList(FIELD_LAYERS);
350
                if (layers != null) {
351
                        for (int i = 0; i < layers.size(); i++) {
352
                                addLayer((ISymbol) layers.get(i));
353
                        }
354
                }
355
        }
356

    
357
        public void saveToState(PersistentState state) throws PersistenceException {
358
                // Save parent fill symbol properties
359
                super.saveToState(state);
360
                // Save own properties
361
                state.set(FIELD_LAYERS, layers);
362
        }
363
        
364
        public static class RegisterPersistence implements Callable {
365

    
366
                public Object call() throws Exception {
367
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
368
                        if( manager.getDefinition(MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
369
                                DynStruct definition = manager.addDefinition(
370
                                                MultiLayerLineSymbol.class,
371
                                                MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
372
                                                MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
373
                                                null, 
374
                                                null
375
                                );
376
                                // Extend the LineSymbol base definition
377
                                definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
378

    
379
                                // Layers
380
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(ILineSymbol.class);
381
                        }
382
                        return Boolean.TRUE;
383
                }
384
                
385
        }
386

    
387
        public static class RegisterSymbol implements Callable {
388

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

    
393
                       shapeTypes = new int[] { Geometry.TYPES.CURVE, Geometry.TYPES.ARC,
394
                                Geometry.TYPES.ELLIPTICARC, Geometry.TYPES.MULTICURVE };
395
                        manager.registerMultiLayerSymbol(ILineSymbol.SYMBOL_NAME,
396
                            shapeTypes,
397
                            MultiLayerLineSymbol.class);
398

    
399
                        return Boolean.TRUE;
400
                }
401
                
402
        }
403

    
404
}