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

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.line.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.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.line.ILineSymbol;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.IMultiLayerLineSymbol;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.ILineStyle;
45
import org.gvsig.tools.ToolsLocator;
46
import org.gvsig.tools.dynobject.DynStruct;
47
import org.gvsig.tools.persistence.PersistenceManager;
48
import org.gvsig.tools.persistence.PersistentState;
49
import org.gvsig.tools.persistence.exception.PersistenceException;
50
import org.gvsig.tools.task.Cancellable;
51
import org.gvsig.tools.util.Callable;
52

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

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

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

    
85
        public ILineStyle getLineStyle() {
86
                /*
87
                 * a multilayer symbol does not define any style, the style
88
                 * of each layer is defined by the layer itself
89
                 */
90
                return null;
91
        }
92

    
93
    public double getLineWidth() {
94
        return lineWidth;
95
    }
96

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

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

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

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

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

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

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

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

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

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

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

    
185
        }
186

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

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

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

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

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

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

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

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

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

    
233

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

    
249
        public boolean removeLayer(ISymbol layer) {
250

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

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

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

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

    
303
        }
304

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

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

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

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

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

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

    
342
                return copy;
343
        }
344

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

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

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

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

    
389
        public static class RegisterSymbol implements Callable {
390

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

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

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

    
406
}