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

History | View | Annotate | Download (12.7 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
                } else {
173
                  for (int i = 0; i < selectionSymbol.getLayerCount(); i++) {
174
                        selectionSymbol.setLayer(i, selectionSymbol.getLayer(i).getSymbolForSelection());
175
                    }
176
                }
177
                return selectionSymbol;
178
        }
179

    
180
        public boolean isSuitableFor(Geometry geom) {
181
              switch(geom.getType()) {
182
                case Geometry.TYPES.CURVE:
183
                case Geometry.TYPES.LINE:
184
                    return true;
185
                }
186
                return false;
187
        }
188

    
189
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
190
                for (int i = 0; layers != null && i < layers.length; i++) {
191
                        layers[i].print(g, at, geom, properties);
192
                }
193

    
194
        }
195

    
196
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
197
                layers[index] = (ILineSymbol) layer;
198
        }
199

    
200
        public void swapLayers(int index1, int index2) {
201
                ISymbol aux1 = getLayer(index1), aux2 = getLayer(index2);
202
                layers[index2] = (ILineSymbol) aux1;
203
                layers[index1] = (ILineSymbol) aux2;
204
        }
205

    
206
        public ISymbol getLayer(int layerIndex) {
207
                return layers[layerIndex];
208
        }
209

    
210
        public int getLayerCount() {
211
                return layers.length;
212
        }
213

    
214
        public void addLayer(ISymbol newLayer) {
215
                addLayer(newLayer, layers.length);
216
        }
217

    
218
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
219

    
220
                if (newLayer == null) {
221
                        return; // null are not allowed
222
                }
223
                ILineSymbol newLine = (ILineSymbol) newLayer;
224
                if (getLayerCount() == 0) {
225
                        // apply the new layer properties to this multilayer
226

    
227
                        setReferenceSystem(newLine.getReferenceSystem());
228
                        setUnit(newLine.getUnit());
229
                        lineWidth = newLine.getLineWidth();
230
                } else {
231
                        if (newLine.getLineWidth() > getLineWidth()) {
232
                                lineWidth = newLine.getLineWidth();
233
                        }
234
                        newLine.setReferenceSystem(getReferenceSystem());
235
                        newLine.setUnit(getUnit());
236
                }
237

    
238
                selectionSymbol = null; /* forces the selection symbol to be re-created
239
                                                                  * next time it is required
240
                                                                  */
241

    
242

    
243
                if (layerIndex < 0 || layers.length < layerIndex) {
244
                        throw new IndexOutOfBoundsException(layerIndex+" < 0 or "+layerIndex+" > "+layers.length);
245
                }
246
                List<ISymbol> newLayers = new ArrayList<ISymbol>();
247
                for (int i = 0; i < layers.length; i++) {
248
                        newLayers.add(layers[i]);
249
                }
250
                try {
251
                        newLayers.add(layerIndex, newLayer);
252
                        layers = (ILineSymbol[])newLayers.toArray(new ILineSymbol[0]);
253
                } catch (ArrayStoreException asEx) {
254
                        throw new ClassCastException(newLayer.getClass().getName()+" is not an ILineSymbol");
255
                }
256
        }
257

    
258
        public boolean removeLayer(ISymbol layer) {
259

    
260
                int capacity = 0;
261
                capacity = layers.length;
262
                List<ILineSymbol> lst = new ArrayList<ILineSymbol>(capacity);
263
                for (int i = 0; i < capacity; i++) {
264
                        lst.add(layers[i]);
265
                }
266
                boolean contains = lst.remove(layer);
267
                layers = (ILineSymbol[])lst.toArray(new ILineSymbol[0]);
268
                return contains;
269
        }
270

    
271
        public int getAlpha() {
272
                // will compute the acumulated opacity
273
                double myAlpha = 0;
274
                for (int i = 0; i < layers.length; i++) {
275
                        double layerAlpha = layers[i].getAlpha()/255D;
276
                        myAlpha += (1-myAlpha)*layerAlpha;
277
                }
278
                int result = (int) Math.round(myAlpha * 255);
279
                return (result>255) ? 255 : result;
280
        }
281

    
282
        public void setAlpha(int outlineAlpha) {
283
                // first, get the biggest alpha in the layers and the index if such layer
284
                int maxAlpha = Integer.MIN_VALUE;
285
                int maxAlphaLayerIndex = 0;
286
                for (int i = 0; i < layers.length; i++) {
287
                        if (layers[i].getAlpha() > maxAlpha) {
288
                                maxAlpha = layers[i].getAlpha();
289
                                maxAlphaLayerIndex = i;
290
                        }
291
                }
292

    
293
                // now, max alpha takes the value of the desired alpha and the rest
294
                // will take a scaled (to biggest alpha) alpha value
295
                for (int i = 0; layers != null && i < layers.length; i++) {
296
                        if (i!=maxAlphaLayerIndex) {
297
                                double scaledAlpha = (double) layers[i].getAlpha()/maxAlpha;
298
                                int myAlpha = (int) (outlineAlpha*scaledAlpha);
299
                                if (myAlpha == 0) {
300
                                        myAlpha = 1;
301
                                }
302
                                layers[i].setAlpha(myAlpha);
303
                        } else {
304
                                int myAlpha = outlineAlpha;
305
                                if (myAlpha == 0) {
306
                                        myAlpha = 1;
307
                                }
308
                                layers[i].setAlpha(myAlpha);
309
                        }
310
                }
311

    
312
        }
313

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

    
321
        public void setReferenceSystem(int system) {
322
                super.setReferenceSystem(system);
323
                for (int i = 0; layers != null && i < layers.length; i++) {
324
                        layers[i].setReferenceSystem(system);
325
                }
326
        }
327

    
328
        public void setCartographicSize(double cartographicSize, Geometry geom) {
329
//                super.setCartographicSize(cartographicSize, shp);
330
                setLineWidth(cartographicSize);
331
        }
332

    
333
        public Object clone() throws CloneNotSupportedException {
334
                MultiLayerLineSymbol copy = (MultiLayerLineSymbol) super.clone();
335

    
336
                // Clone layers
337
                if (layers != null && layers.length > 0) {
338
                        ILineSymbol[] layersCopy = new ILineSymbol[layers.length];
339
                        for (int i = 0; i < layers.length; i++) {
340
                                layersCopy[i] = (ILineSymbol) layers[i].clone();
341
                        }
342
                        copy.layers = layersCopy;
343
                }
344

    
345
                // Clone selection
346
                if (selectionSymbol != null) {
347
                        copy.selectionSymbol = (MultiLayerLineSymbol) selectionSymbol
348
                                        .clone();
349
                }
350

    
351
                return copy;
352
        }
353

    
354
        @SuppressWarnings("unchecked")
355
        public void loadFromState(PersistentState state)
356
                        throws PersistenceException {
357
                // Set parent fill symbol properties
358
                super.loadFromState(state);
359
                // Set own properties
360
                List layers = state.getList(FIELD_LAYERS);
361
                if (layers != null) {
362
                        for (int i = 0; i < layers.size(); i++) {
363
                                addLayer((ISymbol) layers.get(i));
364
                        }
365
                }
366
        }
367

    
368
        public void saveToState(PersistentState state) throws PersistenceException {
369
                // Save parent fill symbol properties
370
                super.saveToState(state);
371
                // Save own properties
372
                state.set(FIELD_LAYERS, layers);
373
        }
374

    
375
        public static class RegisterPersistence implements Callable {
376

    
377
                public Object call() throws Exception {
378
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
379
                        if( manager.getDefinition(MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
380
                                DynStruct definition = manager.addDefinition(
381
                                                MultiLayerLineSymbol.class,
382
                                                MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
383
                                                MULTILAYER_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
384
                                                null,
385
                                                null
386
                                );
387
                                // Extend the LineSymbol base definition
388
                                definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
389

    
390
                                // Layers
391
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(ILineSymbol.class);
392
                        }
393
                        return Boolean.TRUE;
394
                }
395

    
396
        }
397

    
398
        public static class RegisterSymbol implements Callable {
399

    
400
                public Object call() throws Exception {
401
                        int[] shapeTypes;
402
                        SymbolManager manager = MapContextLocator.getSymbolManager();
403

    
404
                       shapeTypes = new int[] { Geometry.TYPES.CURVE, Geometry.TYPES.ARC,
405
                                Geometry.TYPES.ELLIPTICARC, Geometry.TYPES.MULTICURVE };
406
                        manager.registerMultiLayerSymbol(ILineSymbol.SYMBOL_NAME,
407
                            shapeTypes,
408
                            MultiLayerLineSymbol.class);
409

    
410
                        return Boolean.TRUE;
411
                }
412

    
413
        }
414

    
415
}