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

History | View | Annotate | Download (12.6 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
    @Override
181
        public boolean isSuitableFor(Geometry geom) {
182
        return geom.getGeometryType().isTypeOf(Geometry.TYPES.CURVE);
183
        }
184

    
185
    @Override
186
        public void print(Graphics2D g, AffineTransform at, Geometry geom, PrintAttributes properties) {
187
                for (int i = 0; layers != null && i < layers.length; i++) {
188
                        layers[i].print(g, at, geom, properties);
189
                }
190

    
191
        }
192

    
193
        public void setLayer(int index, ISymbol layer) throws IndexOutOfBoundsException {
194
                layers[index] = (ILineSymbol) layer;
195
        }
196

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

    
203
        public ISymbol getLayer(int layerIndex) {
204
                return layers[layerIndex];
205
        }
206

    
207
        public int getLayerCount() {
208
                return layers.length;
209
        }
210

    
211
        public void addLayer(ISymbol newLayer) {
212
                addLayer(newLayer, layers.length);
213
        }
214

    
215
        public void addLayer(ISymbol newLayer, int layerIndex) throws IndexOutOfBoundsException {
216

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

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

    
235
                selectionSymbol = null; /* forces the selection symbol to be re-created
236
                                                                  * next time it is required
237
                                                                  */
238

    
239

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

    
255
        public boolean removeLayer(ISymbol layer) {
256

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

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

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

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

    
309
        }
310

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

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

    
325
        public void setCartographicSize(double cartographicSize, Geometry geom) {
326
//                super.setCartographicSize(cartographicSize, shp);
327
                setLineWidth(cartographicSize);
328
        }
329

    
330
        public Object clone() throws CloneNotSupportedException {
331
                MultiLayerLineSymbol copy = (MultiLayerLineSymbol) super.clone();
332

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

    
342
                // Clone selection
343
                if (selectionSymbol != null) {
344
                        copy.selectionSymbol = (MultiLayerLineSymbol) selectionSymbol
345
                                        .clone();
346
                }
347

    
348
                return copy;
349
        }
350

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

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

    
372
        public static class RegisterPersistence implements Callable {
373

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

    
387
                                // Layers
388
                                definition.addDynFieldList(FIELD_LAYERS).setClassOfItems(ILineSymbol.class);
389
                        }
390
                        return Boolean.TRUE;
391
                }
392

    
393
        }
394

    
395
        public static class RegisterSymbol implements Callable {
396

    
397
                public Object call() throws Exception {
398
                        int[] shapeTypes;
399
                        SymbolManager manager = MapContextLocator.getSymbolManager();
400

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

    
407
                        return Boolean.TRUE;
408
                }
409

    
410
        }
411

    
412
}