Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.mapcontext / org.gvsig.fmap.mapcontext.api / src / main / java / org / gvsig / fmap / mapcontext / rendering / symbols / impl / DefaultSymbolManager.java @ 40611

History | View | Annotate | Download (14.5 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
/*
25
 * AUTHORS (In addition to CIT):
26
 * 2009 {DiSiD Technologies}  {{Task}}
27
 * 
28
 **************************************************************
29
 * Colors from www.ColorBrewer.org by Cynthia A. Brewer,
30
 * Geography, Pennsylvania State University.
31
 * Using groups of 4 colors from the 9 Diverging Schemes
32
 * 4 * 9 = 36 colors
33
 **************************************************************
34
 * 
35
 */
36
package org.gvsig.fmap.mapcontext.rendering.symbols.impl;
37

    
38
import java.awt.Color;
39
import java.io.File;
40
import java.io.FileFilter;
41
import java.io.FileInputStream;
42
import java.io.FileOutputStream;
43
import java.io.IOException;
44
import java.util.Arrays;
45
import java.util.Collections;
46
import java.util.Comparator;
47
import java.util.HashMap;
48
import java.util.Map;
49
import java.util.Random;
50

    
51
import org.gvsig.fmap.mapcontext.MapContextRuntimeException;
52
import org.gvsig.fmap.mapcontext.impl.InvalidRegisteredClassException;
53
import org.gvsig.fmap.mapcontext.impl.RegisteredClassInstantiationException;
54
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
55
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
56
import org.gvsig.fmap.mapcontext.rendering.symbols.IWarningSymbol;
57
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolException;
58
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
59
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolPreferences;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.persistence.PersistenceManager;
62
import org.gvsig.tools.persistence.PersistentState;
63
import org.gvsig.tools.persistence.exception.PersistenceException;
64
import org.gvsig.tools.task.SimpleTaskStatus;
65
import org.gvsig.tools.task.TaskStatusManager;
66

    
67
/**
68
 * Default {@link SymbolManager} implementation.
69
 * 
70
 * @author gvSIG team
71
 */
72
public class DefaultSymbolManager implements SymbolManager {
73

    
74
        private SymbolPreferences symbolPreferences =
75
                        new DefaultSymbolPreferences();
76

    
77
        private Map symbolsByName = Collections.synchronizedMap(new HashMap());
78

    
79
        private Map symbolsByShapeType = Collections.synchronizedMap(new HashMap());
80

    
81
        private Map multiLineSymbolsByName =
82
                        Collections.synchronizedMap(new HashMap());
83

    
84
        private Map multiLineSymbolsByShapeType =
85
                        Collections.synchronizedMap(new HashMap());
86

    
87
        private IWarningSymbol warningSymbol;
88

    
89
        private Object warningSymbolLock = new Object();
90

    
91
        public ISymbol[] loadSymbols(File folder) throws SymbolException {
92
                return loadSymbols(folder, null);
93
        }
94

    
95
        public ISymbol[] loadSymbols(File folder, FileFilter fileFilter)
96
                        throws SymbolException {
97
                // TODO: add symbol caching
98

    
99
                if (folder.exists()) {
100

    
101
                        File[] symbolFiles = null;
102
                        if (fileFilter == null) {
103
                                symbolFiles = folder.listFiles();
104
                        } else {
105
                                symbolFiles = folder.listFiles(fileFilter);
106
                        }
107

    
108
                        if (symbolFiles != null) {
109
                            TaskStatusManager tm = ToolsLocator.getTaskStatusManager();
110
                            SimpleTaskStatus status = tm.createDefaultSimpleTaskStatus("Load symbols");
111
                            status.setRangeOfValues(0, symbolFiles.length);
112
                            status.setAutoremove(true);
113
                            status.add();
114
                            
115
                            /*
116
                             * Sorting by file name before loading.
117
                             * The problem here is that some
118
                             * descriptions can be empty, so sorting using description
119
                             * can have strange behavior. Sorting by file name is not
120
                             * very elegant, though.
121
                             */
122
                status.message("sorting symbols");
123
                                Arrays.sort(symbolFiles, new Comparator() {
124
                                        public int compare( Object o1, Object o2) {
125
                                                File f1 = (File) o1;
126
                                                File f2 = (File) o2;
127
                                                return f1.getName().compareTo(f2.getName());
128
                                        }
129
                                });
130

    
131
                            ISymbol[] symbols = null;
132
                            try {
133
                        symbols = new ISymbol[symbolFiles.length];
134
                        for (int i = 0; i < symbolFiles.length; i++) {
135
                            status.setCurValue(i);
136
                            symbols[i] = loadSymbol(symbolFiles[i]);
137
                            
138
                        }
139

    
140
                            } finally {
141
                                status.terminate();
142
                            }
143
                                return symbols;
144
                        }
145
                }
146

    
147
                return null;
148
        }
149

    
150
        public void saveSymbol(ISymbol symbol, String fileName, File folder)
151
                        throws SymbolException {
152
                saveSymbol(symbol, fileName, folder, false);
153
        }
154

    
155
        public void saveSymbol(ISymbol symbol, String fileName, File folder,
156
                        boolean overwrite) throws SymbolException {
157
                // TODO: add symbol caching
158

    
159
                PersistenceManager persistenceManager = ToolsLocator
160
                                .getPersistenceManager();
161

    
162
                File symbolFile = new File(folder, fileName);
163
                if (!overwrite && symbolFile.exists()) {
164
                        throw new SymbolFileAlreadyExistsException(symbolFile);
165
                }
166

    
167
                try {
168
                        FileOutputStream fos = new FileOutputStream(symbolFile);
169

    
170
                        persistenceManager.saveState(persistenceManager.getState(symbol),
171
                                        fos);
172

    
173
                        fos.flush();
174
                        fos.close();
175
                } catch (PersistenceException e) {
176
                        throw new SaveSymbolException(e);
177
                } catch (IOException e) {
178
                        throw new SaveSymbolException(e);
179
                }
180
        }
181

    
182
        /**
183
         * Loads a persisted symbol from the given file.
184
         */
185
        private ISymbol loadSymbol(File file) throws SymbolException {
186
                if (file.exists()) {
187
                        try {
188
                                FileInputStream fis = new FileInputStream(file);
189

    
190
                                PersistenceManager persistenceManager = ToolsLocator
191
                                                .getPersistenceManager();
192

    
193
                                PersistentState state = persistenceManager.loadState(fis);
194
                                ISymbol symbol = (ISymbol) persistenceManager.create(state);
195

    
196
                                fis.close();
197
                                return symbol;
198
                        } catch (PersistenceException e) {
199
                                throw new LoadSymbolException(e);
200
                        } catch (IOException e) {
201
                                throw new LoadSymbolException(e);
202
                        }
203
                }
204

    
205
                return null;
206
        }
207

    
208
        public SymbolPreferences getSymbolPreferences() {
209
                return symbolPreferences;
210
        }
211

    
212
        public ISymbol createSymbol(String symbolName)
213
                        throws MapContextRuntimeException {
214
                return createSymbol(symbolName, (Class) symbolsByName.get(symbolName),
215
                                ISymbol.class);
216
        }
217

    
218
        public ISymbol createSymbol(int shapeType)
219
                        throws MapContextRuntimeException {
220
                String symbolName =
221
                                (String) symbolsByShapeType.get(new Integer(shapeType));
222

    
223
                return symbolName == null ? null : createSymbol(symbolName);
224
        }
225

    
226
        public ISymbol createSymbol(String symbolName, Color color)
227
                        throws MapContextRuntimeException {
228
                ISymbol symbol = createSymbol(symbolName);
229

    
230
                if (symbol != null) {
231
                        symbol.setColor(color);
232
                }
233

    
234
                return symbol;
235
        }
236

    
237
        public ISymbol createSymbol(int shapeType, Color color)
238
                        throws MapContextRuntimeException {
239
                String symbolName =
240
                                (String) symbolsByShapeType.get(new Integer(shapeType));
241

    
242
                return symbolName == null ? null : createSymbol(symbolName, color);
243
        }
244

    
245
        public IMultiLayerSymbol createMultiLayerSymbol(String symbolName)
246
                        throws MapContextRuntimeException {
247
                return (IMultiLayerSymbol) createSymbol(symbolName,
248
                                (Class) multiLineSymbolsByName.get(symbolName),
249
                                IMultiLayerSymbol.class);
250
        }
251

    
252
        public IMultiLayerSymbol createMultiLayerSymbol(int shapeType)
253
                        throws MapContextRuntimeException {
254
                String symbolName =
255
                                (String) multiLineSymbolsByShapeType.get(new Integer(shapeType));
256

    
257
                return symbolName == null ? null : createMultiLayerSymbol(symbolName);
258
        }
259

    
260
        public void registerSymbol(String symbolName, Class symbolClass)
261
                        throws MapContextRuntimeException {
262
                if (symbolClass == null || !ISymbol.class.isAssignableFrom(symbolClass)) {
263
                        throw new InvalidRegisteredClassException(ISymbol.class,
264
                                        symbolClass, symbolName);
265
                }
266
                symbolsByName.put(symbolName, symbolClass);
267
        }
268

    
269
        public void registerSymbol(String symbolName, int[] shapeTypes,
270
                        Class symbolClass) throws MapContextRuntimeException {
271
                registerSymbol(symbolName, symbolClass);
272
                if (shapeTypes != null) {
273
                        for (int i = 0; i < shapeTypes.length; i++) {
274
                                symbolsByShapeType.put(new Integer(shapeTypes[i]), symbolName);
275
                        }
276
                }
277
        }
278

    
279
        public void registerMultiLayerSymbol(String symbolName, Class symbolClass)
280
                        throws MapContextRuntimeException {
281
                if (symbolClass == null
282
                                || !IMultiLayerSymbol.class.isAssignableFrom(symbolClass)) {
283
                        throw new InvalidRegisteredClassException(IMultiLayerSymbol.class,
284
                                        symbolClass, symbolName);
285
                }
286

    
287
                multiLineSymbolsByName.put(symbolName, symbolClass);
288
        }
289

    
290
        public void registerMultiLayerSymbol(String symbolName, int[] shapeTypes,
291
                        Class symbolClass) throws MapContextRuntimeException {
292
                registerMultiLayerSymbol(symbolName, symbolClass);
293
                if (shapeTypes != null) {
294
                        for (int i = 0; i < shapeTypes.length; i++) {
295
                                multiLineSymbolsByShapeType.put(new Integer(shapeTypes[i]),
296
                                                symbolName);
297
                        }
298
                }
299
        }
300

    
301
        public IWarningSymbol getWarningSymbol(String message, String symbolDesc,
302
                        int symbolDrawExceptionType) throws MapContextRuntimeException {
303
                synchronized (warningSymbolLock) {
304
                        if (warningSymbol == null) {
305
                                warningSymbol = (IWarningSymbol) createSymbol("warning");
306
                        }
307
                }
308

    
309
                // TODO: set those values as parameter values in the draw method.
310
                warningSymbol.setDescription(symbolDesc);
311
                warningSymbol.setMessage(message);
312
                warningSymbol.setDrawExceptionType(symbolDrawExceptionType);
313

    
314
                return warningSymbol;
315
        }
316

    
317
        private ISymbol createSymbol(String symbolName, Class symbolClass,
318
                        Class expectedType) throws MapContextRuntimeException {
319
                ISymbol symbol;
320
                try {
321
                        symbol =
322
                                        (ISymbol) (symbolClass == null ? null
323
                                                        : symbolClass.newInstance());
324
                } catch (InstantiationException e) {
325
                        throw new RegisteredClassInstantiationException(expectedType,
326
                                        symbolClass, symbolName, e);
327
                } catch (IllegalAccessException e) {
328
                        throw new RegisteredClassInstantiationException(expectedType,
329
                                        symbolClass, symbolName, e);
330
                }
331

    
332
                Color the_color = null;
333
                
334
        if (getSymbolPreferences().isDefaultSymbolFillColorAleatory()) {
335
            
336
            the_color = getRandomBrewerBasedColor();
337
            
338
        } else {
339
            // not random
340
            the_color = getSymbolPreferences().getDefaultSymbolFillColor();
341
        }
342
        symbol.setColor(the_color);
343
                // Perform this initialization into the Symbol implementation
344
                // if (symbol instanceof CartographicSupport) {
345
                // CartographicSupport cs = (CartographicSupport) symbol;
346
                // cs.setUnit(getDefaultCartographicSupportMeasureUnit());
347
                // cs
348
                // .setReferenceSystem(getDefaultCartographicSupportReferenceSystem();
349
                // }
350

    
351
                return symbol;
352
        }
353
        
354
        public void setSymbolPreferences(SymbolPreferences symbolPreferences) {
355
                this.symbolPreferences = symbolPreferences;
356
        }
357
        
358
        /**
359
         * 
360
         * @param col
361
         * @return color 1/3 closer to black
362
         */
363
        public static Color darker(Color col) {
364
            return new Color(
365
                (2 * col.getRed()) / 3,
366
                (2 * col.getGreen()) / 3,
367
                (2 * col.getBlue()) / 3,
368
                col.getAlpha());
369
        }
370

    
371
        /**
372
         * 
373
         * @param col
374
         * @return color 1/3 closer to white
375
         */
376
        public static Color lighter(Color col) {
377
            Color resp = invert(col);
378
            resp = darker(resp);
379
            return invert(resp);
380
        }
381
        
382
        /**
383
         * 
384
         * @param col
385
         * @return inverted color (inverts each band, same alpha)
386
         */
387
        public static Color invert(Color col) {
388
        return new Color(
389
            255 - col.getRed(),
390
            255 - col.getGreen(),
391
            255 - col.getBlue(),
392
            col.getAlpha());
393
        }
394
        
395
        private static Color getRandomBrewerBasedColor() {
396
            
397
            int ind = rnd.nextInt(BREWER_COLOR.length);
398
            Color resp = BREWER_COLOR[ind]; 
399
            ind = rnd.nextInt(100);
400
            if (ind > 66) {
401
                resp = darker(resp);
402
            } else {
403
                if (ind > 33) {
404
                    resp = lighter(resp);
405
                }
406
                // ...else resp remains the same
407
            }
408
            
409
            // finally add some dark noise 
410
            resp = addDarkNoise(resp);
411
            return resp;
412
        }
413
        
414
    private static Color addDarkNoise(Color c) {
415
        int r = Math.max(0, c.getRed() - rnd.nextInt(30));
416
        int g = Math.max(0, c.getGreen() - rnd.nextInt(30));
417
        int b = Math.max(0, c.getBlue() - rnd.nextInt(30));
418
        return new Color(r, g, b, c.getAlpha());
419
    }
420

    
421
    private static Color[] BREWER_COLOR = new Color[36];
422
    private static final Random rnd = new Random();
423
        
424
        static {
425
            /**
426
             * Colors from www.ColorBrewer.org by Cynthia A. Brewer,
427
             * Geography, Pennsylvania State University.
428
             *
429
             * Using groups of 4 colors from the 9 Diverging Schemes
430
             * 4 * 9 = 36 colors
431
             */
432
            BREWER_COLOR[0] = new Color(230, 97, 1);
433
            BREWER_COLOR[1] = new Color(253, 184, 99);
434
            BREWER_COLOR[2] = new Color(178, 171, 210);
435
            BREWER_COLOR[3] = new Color(94, 60, 153);
436
            BREWER_COLOR[4] = new Color(166, 97, 26);
437
            BREWER_COLOR[5] = new Color(223, 194, 125);
438
            BREWER_COLOR[6] = new Color(128, 205, 193);
439
            BREWER_COLOR[7] = new Color(1, 133, 113);
440
            BREWER_COLOR[8] = new Color(123, 50, 148);
441
            BREWER_COLOR[9] = new Color(194, 165, 207);
442
            BREWER_COLOR[10] = new Color(166, 219, 160);
443
            BREWER_COLOR[11] = new Color(0, 136, 55);
444
            BREWER_COLOR[12] = new Color(208, 28, 139);
445
            BREWER_COLOR[13] = new Color(241, 182, 218);
446
            BREWER_COLOR[14] = new Color(184, 225, 134);
447
            BREWER_COLOR[15] = new Color(77, 172, 38);
448
            BREWER_COLOR[16] = new Color(202, 0, 32);
449
            BREWER_COLOR[17] = new Color(244, 165, 130);
450
            BREWER_COLOR[18] = new Color(146, 197, 222);
451
            BREWER_COLOR[19] = new Color(5, 113, 176);
452
            BREWER_COLOR[20] = new Color(202, 0, 32);
453
            BREWER_COLOR[21] = new Color(244, 165, 130);
454
            BREWER_COLOR[22] = new Color(186, 186, 186);
455
            BREWER_COLOR[23] = new Color(64, 64, 64);
456
            BREWER_COLOR[24] = new Color(215, 25, 28);
457
            BREWER_COLOR[25] = new Color(253, 174, 97);
458
            BREWER_COLOR[26] = new Color(171, 217, 233);
459
            BREWER_COLOR[27] = new Color(44, 123, 182);
460
            BREWER_COLOR[28] = new Color(215, 25, 28);
461
            BREWER_COLOR[29] = new Color(253, 174, 97);
462
            BREWER_COLOR[30] = new Color(171, 221, 164);
463
            BREWER_COLOR[31] = new Color(43, 131, 186);
464
            BREWER_COLOR[32] = new Color(215, 25, 28);
465
            BREWER_COLOR[33] = new Color(253, 174, 97);
466
            BREWER_COLOR[34] = new Color(166, 217, 106);
467
            BREWER_COLOR[35] = new Color(26, 150, 65);
468
        }
469

    
470
        
471
}