Statistics
| Revision:

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

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

    
52
import javax.print.attribute.PrintRequestAttributeSet;
53

    
54
import org.cresques.cts.ICoordTrans;
55
import org.gvsig.fmap.data.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

    
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 #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
    /*
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 ReadException {
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
        Envelope 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

    
208
        ICoordTrans ct = getCoordTrans();
209

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

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

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

    
224
            if (geom.fastIntersects(elExtent.getMinimum(0),
225
                        elExtent.getMinimum(1), elExtent.getLength(0), elExtent.getLength(1)))
226
             {
227
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
228
                if (theSymbol == null)
229
                        continue;
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
        return -1;
256

    
257
    }
258

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

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

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

    
284
    }
285

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

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

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

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

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

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

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

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

    
389
        }
390

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

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

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

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

    
451
                                fullExtent.add(rAux);
452
                        }
453
                }
454
        }
455

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

    
471
        }
472

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

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