Statistics
| Revision:

svn-gvsig-desktop / branches / v10 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / layers / GraphicLayer.java @ 20100

History | View | Annotate | Download (16.5 KB)

1
/*
2
 * Created on 19-sep-2005
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
 *
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
package com.iver.cit.gvsig.fmap.layers;
45

    
46
import java.awt.Graphics2D;
47
import java.awt.geom.Rectangle2D;
48
import java.awt.image.BufferedImage;
49
import java.util.ArrayList;
50
import java.util.Collection;
51

    
52
import javax.print.attribute.PrintRequestAttributeSet;
53

    
54
import org.cresques.cts.ICoordTrans;
55

    
56
import com.iver.cit.gvsig.fmap.DriverException;
57
import com.iver.cit.gvsig.fmap.ViewPort;
58
import com.iver.cit.gvsig.fmap.core.IGeometry;
59
import com.iver.cit.gvsig.fmap.core.ISymbol;
60
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
61
import com.iver.cit.gvsig.fmap.core.v02.FSymbol;
62
import com.iver.cit.gvsig.fmap.rendering.FGraphic;
63
import com.iver.utiles.swing.threads.Cancellable;
64
import com.vividsolutions.jts.index.ItemVisitor;
65
import com.vividsolutions.jts.index.SpatialIndex;
66
import com.vividsolutions.jts.index.quadtree.Quadtree;
67

    
68
/**
69
 * <p><code>GraphicLayer</code> represents a layer with graphical items, that are geometries with
70
 *  a symbol and handlers associated.</p>
71
 * 
72
 * <p>The internal graphical items are independent to each other and can be selected separately. There is a <i>bit set</i> to
73
 * define which item are selected. They, will be drawn with handlers, that according to the particular
74
 * implementation of each one, can allow user to move, center, deform, ... each graphical item.</p>
75
 * 
76
 * @see FLyrDefault
77
 */
78
public class GraphicLayer extends FLyrDefault {
79
        /**
80
         * Internal list with all graphic items of this layer.
81
         * 
82
         * @see #addGraphic(FGraphic)
83
         * @see #clearAllGraphics()
84
         * @see #getGraphic(int)
85
         * @see #getGraphicByObjectTag(Object)
86
         * @see #inserGraphics(int, Collection)
87
         * @see #insertGraphic(int, FGraphic)
88
         * @see #removeGraphic(FGraphic)
89
         * @see #removeGraphic(int)
90
         * @see #getNumGraphics()
91
         */
92
    private ArrayList graphics = new ArrayList();
93

    
94
        /**
95
         * Internal list with all symbols of this layer.
96
         * 
97
         * @see #addSymbol(ISymbol)
98
         * @see #clearSymbolsGraphics()
99
         */
100
    private ArrayList symbols = new ArrayList();
101

    
102
        /**
103
         * Describes a rectangle defined by a location (x, y) and dimension, that represents this layer position
104
         *  and dimension.
105
         * 
106
         * @see #getFullExtent()
107
         * @see #reCalculateFullExtent()
108
         */
109
    private Rectangle2D fullExtent;
110

    
111
        /**
112
         * An optimal index according a quadtree for fast access to spatial data.
113
         */
114
    private SpatialIndex spatialIndex = new Quadtree();
115

    
116
        /**
117
         * A set of boolean items that specifies which graphic items of this layer are selected.
118
         * 
119
         * @see #getSelection()
120
         * @see #setSelection(FBitSet)
121
         */
122
    private FBitSet selection = new FBitSet();
123

    
124
        /**
125
         * <p>Creates a new <code>GraphicLayer</code> instance.</p>
126
         * 
127
         * @see FLyrDefault#FLyrDefault()
128
         */
129
    public GraphicLayer() {
130
        super();
131
        System.err.println("GraphicLayer: Constructor");
132
    }
133

    
134
    /*
135
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#getFullExtent()
136
     */
137
    public Rectangle2D getFullExtent() throws DriverException {
138
        return fullExtent;
139
    }
140

    
141
    /*
142
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, com.iver.cit.gvsig.fmap.ViewPort, com.iver.utiles.swing.threads.Cancellable, double)
143
     */
144
    public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale) throws DriverException {
145
        if (isVisible() && isWithinScale(scale)){
146
            drawGraphics(image, g, viewPort, cancel);
147
            }
148
    }
149

    
150
    /**
151
     * <p>Processes all graphic items of this layer according to the <i>visitor pattern</i>. This
152
     *  operation can be canceled at any time.</p> 
153
     * 
154
     * @param visitor object that allows visit each graphic item
155
     * @param cancel shared object that determines if this layer can continue being drawn
156
     */
157
    public void process(ItemVisitor visitor, Cancellable cancel)
158
    {
159
        int numReg;
160

    
161
        for (numReg = 0; numReg < graphics.size(); numReg++) {
162
                if (cancel != null){
163
                        if (cancel.isCanceled()) {
164
                                break;
165
                    }
166
            }
167
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
168
            visitor.visitItem(theGraphic);
169
        }
170
    }
171

    
172
    /*
173
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#print(java.awt.Graphics2D, com.iver.cit.gvsig.fmap.ViewPort, com.iver.utiles.swing.threads.Cancellable, double, javax.print.attribute.PrintRequestAttributeSet)
174
     */
175
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintRequestAttributeSet properties) throws DriverException {
176
        if (isVisible() && isWithinScale(scale)){
177
            drawGraphics(null, g, viewPort, cancel);
178
            }
179
    }
180

    
181
    /**
182
     * <p>Draws each graphic item of this layer that it's associated symbol is also in this layer, and its
183
     *  geometry intersects with the extent currently covered by the view (of the {@link ViewPort ViewPort}). If
184
     *  the graphic item is selected, will also draw its selection handlers.</p> 
185
     * 
186
     * @param image buffer used sometimes instead <code>g</code> to accelerate the draw. For example, if two points are as closed that can't be distinguished, draws only one.
187
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
188
         * @param viewPort the information for drawing the layers
189
         * @param cancel an object thread that implements the {@link Cancellable Cancellable} interface, and will allow to cancel the draw
190
         * 
191
     * @see #draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
192
     * @see #print(Graphics2D, ViewPort, Cancellable, double, PrintRequestAttributeSet)
193
     */
194
    private void drawGraphics(BufferedImage image, Graphics2D g,
195
            ViewPort viewPort, Cancellable cancel)
196
    {
197
        int numReg;
198
        Rectangle2D elExtent = viewPort.getAdjustedExtent();
199
        if (elExtent == null) return;
200

    
201
        //int anchoMapa;
202
        //int altoMapa;
203
        //double anchoReal;
204
        //double altoReal;
205
        //double escala;
206
        ISymbol theSymbol = null;
207
        // System.out.println("Dibujando gr?ficos...(" + graphics.size() + ")");
208

    
209
        ICoordTrans ct = getCoordTrans();
210

    
211
        for (numReg = 0; numReg < graphics.size(); numReg++) {
212
            if (cancel.isCanceled()) {
213
                break;
214
            }
215

    
216
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
217
            IGeometry geom = theGraphic.getGeom();
218

    
219
            // Modificaci?n para Jorge, para que le reproyecte los gr?ficos.
220
                        if (ct != null) {
221
                        geom = geom.cloneGeometry();
222
                                geom.reProject(ct);
223
                        }
224

    
225
            if (geom.fastIntersects(elExtent.getMinX(),
226
                        elExtent.getMinY(), elExtent.getWidth(), elExtent.getHeight()))
227
             {
228
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
229
                if (theSymbol == null)
230
                        continue;
231
                if (selection.get(numReg)) // Si est? seleccinado
232
                {
233
                        FGraphicUtilities.DrawHandlers(g, viewPort.getAffineTransform(), geom.getHandlers(IGeometry.SELECTHANDLER), (FSymbol)theSymbol);
234
                }
235
                else
236
                {
237
                        theGraphic.draw(g, viewPort, theSymbol);
238
                }
239
            }
240
        }
241
    }
242

    
243
    /**
244
     * <p>Adds a new symbol to the graphic layer, and, if success, returns the last index of the internal
245
     *  list of symbols.</p>
246
     * 
247
     * @param newSymbol the new symbol
248
     * @return last index of the internal list of symbols if success, -1 otherwise
249
     * 
250
     * @see #clearSymbolsGraphics()
251
     */
252
    public int addSymbol(ISymbol newSymbol)
253
    {
254
        if (symbols.add(newSymbol))
255
            return symbols.size()-1;
256
        return -1;
257

    
258
    }
259

    
260
    /**
261
     * <p>Adds a new graphic item to the graphic layer, and, if success, sets as new extent the graphic's
262
     *  one if this layer hadn't, otherwise sets as new extent the union of both.</p>
263
     * 
264
     * @param g the new graphic item
265
     * 
266
     * @see #insertGraphic(int, FGraphic)
267
     * @see #inserGraphics(int, Collection)
268
     */
269
    public void addGraphic(FGraphic g)
270
    {
271
        if (graphics.add(g))
272
        {
273

    
274
//                spatialIndex.insert(g.getGeom().getBounds2D())
275
            if (fullExtent == null) {
276
                fullExtent = g.getGeom().getBounds2D();
277
            } else {
278
                fullExtent.add(g.getGeom().getBounds2D());
279
            }
280

    
281
//            return graphics.size()-1;
282
        }
283
//        return -1;
284

    
285
    }
286

    
287
    /**
288
     * <p>Adds a new graphic item to the graphic layer at the position specified of the internal list, and, if success,
289
     *  sets as new extent the graphic's one if this layer hadn't, otherwise sets as new extent the union of both.</p>
290
     * 
291
     * @param position the index of the element to insert 
292
     * @param g the new graphic item
293
     * 
294
     * @see #inserGraphics(int, Collection)
295
     * @see #addGraphic(FGraphic)
296
     */
297
    public void insertGraphic(int position, FGraphic g) {
298
            graphics.add(position, g);
299
        if (fullExtent == null) {
300
            fullExtent = g.getGeom().getBounds2D();
301
        } else {
302
            fullExtent.add(g.getGeom().getBounds2D());
303
        }
304
    }
305

    
306
    /**
307
     * Removes all graphic items from this layer. The internal list of graphic items will be empty
308
     *  after this call returns, and layer won't have extent.
309
     *  
310
     * @see #removeGraphic(FGraphic)
311
     * @see #removeGraphic(int)
312
     */
313
    public void clearAllGraphics()
314
    {
315
        System.err.println("Clear all graphics. Antes hab?a " + graphics.size());
316
        graphics.clear();
317
        fullExtent = null;
318
    }
319

    
320
    /**
321
     * Removes all symbols from this layer. The internal list of symbols will be empty
322
     *  after this call returns.
323
     *  
324
     * @see #addSymbol(ISymbol)
325
     */
326
    public void clearSymbolsGraphics()
327
    {
328
        symbols.clear();
329
    }
330

    
331
    /**
332
     * <p>Gets a set of boolean values that specifies which graphic items of this layer are selected.</p>
333
     * 
334
     * @return a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item 
335
     *  that has the same position in the internal list of graphic items of this layer, and to <code>false</code> if isn't selected
336
     *  
337
     * @see #setSelection(FBitSet)
338
     */
339
        public FBitSet getSelection() {
340
                return selection;
341
        }
342

    
343
        /**
344
     * <p>Sets a set of boolean values that specifies which graphic items of this layer are selected.</p>
345
     * 
346
     * @param selection a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item 
347
     *  that has the same position in the internal list of graphic items of this layer, and to <code>false</code> if isn't selected
348
     *  
349
     * @see #getSelection()
350
         */
351
        public void setSelection(FBitSet selection) {
352
                this.selection = selection;
353
        }
354

    
355
        /**
356
         * Returns a bit set that reports which graphic items <i>(geometries)</i>, intersect with
357
         *  the rectangle <code>r</code>.
358
         * 
359
         * @param r the <code>Rectangle2D</code> to be intersected with some geometries of this layer
360
         * @return a <code>FBitSet</code> which <code>true</code> bits represent the geometries of this layer
361
         *  that intersect with the rectangle
362
         * 
363
         * @see IGeometry#intersects(Rectangle2D)
364
         */
365
        public FBitSet queryByRect(Rectangle2D r) {
366
                FBitSet newSel = new FBitSet();
367
        for (int numReg = 0; numReg < graphics.size(); numReg++) {
368

    
369
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
370
            IGeometry geom = theGraphic.getGeom();
371
            if (geom.intersects(r))
372
            {
373
                    newSel.set(numReg);
374
            }
375
        }
376
        return newSel;
377
        }
378

    
379
        /**
380
         * Removes a graphic item and recalculates the extent of this layer.
381
         * 
382
         * @param graphic the graphic item to be removed
383
         * 
384
         * @see #removeGraphic(int)
385
         * @see #clearAllGraphics()
386
         */
387
        public void removeGraphic(FGraphic graphic) {
388
                graphics.remove(graphic);
389
                reCalculateFullExtent();
390
        }
391

    
392
        /**
393
         * <p>Fast remove: removes only a graphic item of this layer.</p>
394
         * <p>Remember to call {@linkplain #reCalculateFullExtent()} when you finish removing graphics.</p>
395
         *  
396
         * @param graphicIndex the graphic item to be removed
397
         * 
398
         * @see #removeGraphic(FGraphic)
399
         * @see #clearAllGraphics()
400
         */
401
        public void removeGraphic(int graphicIndex) {
402
                graphics.remove(graphicIndex);
403
        }
404

    
405
        /**
406
         * Returns the item at the specified position in the internal list of graphics.
407
         * 
408
         * @param idGraphic index of item to return
409
         * @return the item at the specified position in the internal list of graphics
410
         * 
411
         * @see #getGraphicByObjectTag(Object)
412
         * @see #getNumGraphics()
413
         */
414
        public FGraphic getGraphic(int idGraphic) {
415
                return (FGraphic) graphics.get(idGraphic);
416
        }
417

    
418
        /**
419
         * Returns the graphic item of this layer, that has the specified object tag.
420
         * 
421
         * @param objectTag the tag of the item to return 
422
         * @return the item that has the specified object tag, or <code>null</code> if there was no item that had it
423
         * 
424
         * @see #getGraphic(int)
425
         * @see #getNumGraphics()
426
         */
427
        public FGraphic getGraphicByObjectTag(Object objectTag) {
428
        for (int i = 0; i < graphics.size(); i++) {
429
             FGraphic theGraphic = (FGraphic) graphics.get(i);
430
             if (theGraphic.getObjectTag() == objectTag)
431
                     return theGraphic;
432
         }
433
        return null;
434
        }
435

    
436
        /**
437
         * Returns the number of graphic items in this layer.
438
         *
439
         * @return the number of graphic items in this list
440
         * 
441
         * @see #addGraphic(FGraphic)
442
         * @see #inserGraphics(int, Collection)
443
         * @see #insertGraphic(int, FGraphic)
444
         * @see #clearAllGraphics()
445
         * @see #removeGraphic(FGraphic)
446
         * @see #removeGraphic(int)
447
         * @see #getGraphic(int)
448
         */
449
        public int getNumGraphics() {
450
                return graphics.size();
451
        }
452

    
453
        /**
454
         * Recalculates the full extent of this layer as the union of the bounds 2D
455
         *  of all internal graphic items.
456
         */
457
        public void reCalculateFullExtent(){
458
                if (graphics.size() > 0) {
459
                        FGraphic g = (FGraphic) graphics.get(0);
460
                        fullExtent = g.getGeom().getBounds2D();
461
                        for (int i = 1; i < graphics.size(); i++) {
462
                                g = (FGraphic) graphics.get(i);
463
                                Rectangle2D rAux = g.getGeom().getBounds2D();
464

    
465
                                fullExtent.add(rAux);
466
                        }
467
                }
468
        }
469

    
470
        /**
471
         * <p>Inserts all of the elements in the specified {@link Collection Collection} into the internal list of graphic items,
472
         *  starting at the specified position. Shifts the element currently at that position (if there was any) and any
473
         *  subsequent elements to the right (increasing their indices). The new elements will appear in the list
474
         *  in the order that they are returned by the specified collection's iterator.</p>
475
         * 
476
         * @param index index where starting to insert the elements from the specified collection
477
         * @param c elements to be inserted into this list
478
         * 
479
         * @see #insertGraphic(int, FGraphic)
480
         * @see #addGraphic(FGraphic)
481
         */
482
        public void inserGraphics(int index, Collection c) {
483
                graphics.addAll(index, c);
484
        }
485

    
486
        /**
487
         * <p>Fast clone implementation: creates and returns a clone of this layer.</p>
488
         * <p>Symbols and graphic items aren't <i>deepcloned</i> to
489
         *  avoid unnecessary memory consumption.</p>
490
         * 
491
         * @throws Exception any exception produced during the cloning of this layer.
492
         * 
493
         * @return the new graphic layer
494
         */
495
        public FLayer cloneLayer() throws Exception {
496
                GraphicLayer lyr = new GraphicLayer();
497
                for (int i =0; i < symbols.size(); i++)
498
                {
499
                        lyr.addSymbol((ISymbol) symbols.get(i));
500
                }
501
                for (int i =0; i < graphics.size(); i++)
502
                {
503
                        lyr.addGraphic((FGraphic) graphics.get(i));
504
                }
505

    
506
                return lyr;
507
        }
508
}