Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / layers / GraphicLayer.java @ 29272

History | View | Annotate | Download (16.9 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 org.gvsig.fmap.mapcontext.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
import java.util.Set;
52

    
53
import org.cresques.cts.ICoordTrans;
54
import org.gvsig.compat.print.PrintAttributes;
55
import org.gvsig.fmap.dal.exception.ReadException;
56
import org.gvsig.fmap.geom.Geometry;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.mapcontext.ViewPort;
59
import org.gvsig.fmap.mapcontext.rendering.legend.FGraphic;
60
import org.gvsig.fmap.mapcontext.rendering.symbols.FGraphicUtilities;
61
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
62
import org.gvsig.tools.task.Cancellable;
63

    
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 #getFullEnvelope()
107
         * @see #reCalculateFullExtent()
108
         */
109
    private Envelope 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
    }
132

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

    
140
    /*
141
     * @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)
142
     */
143
    public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale) throws ReadException {
144
        if (isVisible() && isWithinScale(scale)){
145
            drawGraphics(image, g, viewPort, cancel);
146
            }
147
    }
148

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

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

    
170
    }
171

    
172
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintAttributes properties) throws ReadException {
173
        if (isVisible() && isWithinScale(scale)){
174
            drawGraphics(null, g, viewPort, cancel);
175
            }
176
    }
177

    
178
    /**
179
     * <p>Draws each graphic item of this layer that it's associated symbol is also in this layer, and its
180
     *  geometry intersects with the extent currently covered by the view (of the {@link ViewPort ViewPort}). If
181
     *  the graphic item is selected, will also draw its selection handlers.</p>
182
     *
183
     * @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.
184
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
185
         * @param viewPort the information for drawing the layers
186
         * @param cancel an object thread that implements the {@link Cancellable Cancellable} interface, and will allow to cancel the draw
187
         *
188
     * @see #draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
189
     * @see #print(Graphics2D, ViewPort, Cancellable, double, PrintAttributes)
190
     */
191
    private void drawGraphics(BufferedImage image, Graphics2D g,
192
            ViewPort viewPort, Cancellable cancel)
193
    {
194
        int numReg;
195
        Envelope elExtent = viewPort.getAdjustedExtent();
196
        if (elExtent == null) {
197
                        return;
198
                }
199

    
200
        //int anchoMapa;
201
        //int altoMapa;
202
        //double anchoReal;
203
        //double altoReal;
204
        //double escala;
205
        ISymbol theSymbol = null;
206

    
207
        ICoordTrans ct = getCoordTrans();
208

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

    
214
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
215
            Geometry geom = theGraphic.getGeom();
216

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

    
223
            if (geom.fastIntersects(elExtent.getMinimum(0),
224
                        elExtent.getMinimum(1), elExtent.getLength(0), elExtent.getLength(1)))
225
             {
226
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
227
                if (theSymbol == null) {
228
                                        continue;
229
                                }
230
                if (selection.get(numReg)) // Si est? seleccinado
231
                {
232
                        FGraphicUtilities.DrawHandlers(g, viewPort.getAffineTransform(), geom.getHandlers(Geometry.SELECTHANDLER), theSymbol);
233
                }
234
                else
235
                {
236
                        theGraphic.draw(g, viewPort, theSymbol);
237
                }
238
            }
239
        }
240
    }
241

    
242
    /**
243
     * <p>Adds a new symbol to the graphic layer, and, if success, returns the last index of the internal
244
     *  list of symbols.</p>
245
     *
246
     * @param newSymbol the new symbol
247
     * @return last index of the internal list of symbols if success, -1 otherwise
248
     *
249
     * @see #clearSymbolsGraphics()
250
     */
251
    public int addSymbol(ISymbol newSymbol)
252
    {
253
        if (symbols.add(newSymbol)) {
254
                        return symbols.size()-1;
255
                }
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().getEnvelope();
277
            } else {
278
                fullExtent.add(g.getGeom().getEnvelope());
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().getEnvelope();
301
        } else {
302
            fullExtent.add(g.getGeom().getEnvelope());
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
        graphics.clear();
316
        fullExtent = null;
317
    }
318

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

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

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

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

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

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

    
390
        }
391

    
392
        /**
393
         * Returns the item at the specified position in the internal list of graphics.
394
         *
395
         * @param idGraphic index of item to return
396
         * @return the item at the specified position in the internal list of graphics
397
         *
398
         * @see #getGraphicByObjectTag(Object)
399
         * @see #getNumGraphics()
400
         */
401
        public FGraphic getGraphic(int idGraphic) {
402
                return (FGraphic) graphics.get(idGraphic);
403
        }
404

    
405
        /**
406
         * Returns the graphic item of this layer, that has the specified object tag.
407
         *
408
         * @param objectTag the tag of the item to return
409
         * @return the item that has the specified object tag, or <code>null</code> if there was no item that had it
410
         *
411
         * @see #getGraphic(int)
412
         * @see #getNumGraphics()
413
         */
414
        public FGraphic getGraphicByObjectTag(Object objectTag) {
415
        for (int i = 0; i < graphics.size(); i++) {
416
             FGraphic theGraphic = (FGraphic) graphics.get(i);
417
             if (theGraphic.getObjectTag() == objectTag) {
418
                                return theGraphic;
419
                        }
420
         }
421
        return null;
422
        }
423

    
424
        /**
425
         * Returns the number of graphic items in this layer.
426
         *
427
         * @return the number of graphic items in this list
428
         *
429
         * @see #addGraphic(FGraphic)
430
         * @see #inserGraphics(int, Collection)
431
         * @see #insertGraphic(int, FGraphic)
432
         * @see #clearAllGraphics()
433
         * @see #removeGraphic(FGraphic)
434
         * @see #removeGraphic(int)
435
         * @see #getGraphic(int)
436
         */
437
        public int getNumGraphics() {
438
                return graphics.size();
439
        }
440

    
441
        /**
442
         * Recalculates the full extent of this layer as the union of the bounds 2D
443
         *  of all internal graphic items.
444
         */
445
        private void reCalculateFullExtent(){
446
                if (graphics.size() > 0) {
447
                        FGraphic g = (FGraphic) graphics.get(0);
448
                        fullExtent = g.getGeom().getEnvelope();
449
                        for (int i = 1; i < graphics.size(); i++) {
450
                                g = (FGraphic) graphics.get(i);
451
                                Envelope rAux = g.getGeom().getEnvelope();
452

    
453
                                fullExtent.add(rAux);
454
                        }
455
                }
456
        }
457

    
458
        /**
459
         * <p>Inserts all of the elements in the specified {@link Collection Collection} into the internal list of graphic items,
460
         *  starting at the specified position. Shifts the element currently at that position (if there was any) and any
461
         *  subsequent elements to the right (increasing their indices). The new elements will appear in the list
462
         *  in the order that they are returned by the specified collection's iterator.</p>
463
         *
464
         * @param index index where starting to insert the elements from the specified collection
465
         * @param c elements to be inserted into this list
466
         *
467
         * @see #insertGraphic(int, FGraphic)
468
         * @see #addGraphic(FGraphic)
469
         */
470
        public void inserGraphics(int index, Collection c) {
471
                graphics.addAll(index, c);
472

    
473
        }
474

    
475
        /**
476
         * <p>Fast remove: removes only a graphic item of this layer.</p>
477
         * <p>Remember to call {@linkplain #reCalculateFullExtent()} when you finish removing graphics.</p>
478
         *
479
         * @param graphicIndex the graphic item to be removed
480
         *
481
         * @see #removeGraphic(FGraphic)
482
         * @see #clearAllGraphics()
483
         */
484
        public void removeGraphic(int graphicIndex) {
485
                graphics.remove(graphicIndex);
486
        }
487

    
488
        /**
489
          * <p>Searches for the first symbol <code>sym</code>, testing for equality using the equals method.</p>
490
          *
491
          * @param sym a symbol
492
          * @return the index of the first occurrence of <code>sym</code>; returns -1 if the object is not found.
493
          */
494
        public int getSymbol(ISymbol sym) {
495
                if (symbols.contains(sym)) {
496
                        return symbols.indexOf(sym);
497
                }
498
                return -1;
499
        }
500

    
501
        /*
502
         * (non-Javadoc)
503
         * 
504
         * @see org.gvsig.metadata.Metadata#getMetadataChildren()
505
         */
506
        public Set getMetadataChildren() {
507
                return null;
508
        }
509

    
510
        /*
511
         * (non-Javadoc)
512
         * 
513
         * @see org.gvsig.metadata.Metadata#getMetadataID()
514
         */
515
        public Object getMetadataID() {
516
                if (this.getName() != null) {
517
                        return "GraphicLayer(" + this.getName() + ")";
518
                } else {
519
                        return "GraphicLayer";
520
                }
521
        }
522

    
523
        /*
524
         * (non-Javadoc)
525
         * 
526
         * @see org.gvsig.metadata.Metadata#getMetadataName()
527
         */
528
        public String getMetadataName() {
529
                if (this.getName() != null) {
530
                        return "Graphic Layer '" + this.getName() + "'";
531
                } else {
532
                        return "Graphic Layer";
533
                }
534
        }
535
}