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 / line / impl / MultiLayerLineSymbol.java @ 34111

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.style.ILineStyle;
42
import org.gvsig.tools.ToolsLocator;
43
import org.gvsig.tools.dynobject.DynStruct;
44
import org.gvsig.tools.persistence.PersistenceManager;
45
import org.gvsig.tools.persistence.PersistentState;
46
import org.gvsig.tools.persistence.exception.PersistenceException;
47
import org.gvsig.tools.task.Cancellable;
48
import org.gvsig.tools.util.Callable;
49

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
177
        public String getClassName() {
178
                return getClass().getName();
179
        }
180

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

    
186
        }
187

    
188
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
189
                layers[index] = (ILineSymbol) layer;
190
        }
191

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

    
198
        public ISymbol getLayer(int layerIndex) {
199
                return layers[layerIndex];
200
        }
201

    
202
        public int getLayerCount() {
203
                return layers.length;
204
        }
205

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

    
210
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
211

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

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

    
230
                selectionSymbol = null; /* forces the selection symbol to be re-created
231
                                                                  * next time it is required
232
                                                                  */
233

    
234

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

    
250
        public boolean removeLayer(ISymbol layer) {
251

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

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

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

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

    
304
        }
305

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

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

    
320
        public void setCartographicSize(double cartographicSize, Geometry geom) {
321
//                super.setCartographicSize(cartographicSize, shp);
322
                setLineWidth(cartographicSize);
323
        }
324

    
325
        public Object clone() throws CloneNotSupportedException {
326
                MultiLayerLineSymbol copy = (MultiLayerLineSymbol) super.clone();
327

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

    
337
                // Clone selection
338
                if (selectionSymbol != null) {
339
                        copy.selectionSymbol = (MultiLayerLineSymbol) selectionSymbol
340
                                        .clone();
341
                }
342

    
343
                return copy;
344
        }
345

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

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

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

    
382
                                // Layers
383
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(ILineSymbol.class);
384
                        }
385
                        return Boolean.TRUE;
386
                }
387
                
388
        }
389

    
390
        public static class RegisterSymbol implements Callable {
391

    
392
                public Object call() throws Exception {
393
                        int[] shapeTypes;
394
                        SymbolManager manager = MapContextLocator.getSymbolManager();
395

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

    
402
                        return Boolean.TRUE;
403
                }
404
                
405
        }
406

    
407
}