Statistics
| Revision:

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

History | View | Annotate | Download (16.4 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.data.ReadException;
56
import org.gvsig.fmap.geom.Geometry;
57
import org.gvsig.fmap.mapcontext.ViewPort;
58
import org.gvsig.fmap.mapcontext.rendering.legend.FGraphic;
59
import org.gvsig.fmap.mapcontext.rendering.symbols.FGraphicUtilities;
60
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
61

    
62
import com.iver.utiles.swing.threads.Cancellable;
63
import com.vividsolutions.jts.index.ItemVisitor;
64
import com.vividsolutions.jts.index.SpatialIndex;
65
import com.vividsolutions.jts.index.quadtree.Quadtree;
66

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

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

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

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

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

    
123
        /**
124
         * <p>Creates a new <code>GraphicLayer</code> instance.</p>
125
         *
126
         * @see FLyrDefault#FLyrDefault()
127
         */
128
    public GraphicLayer() {
129
        super();
130
    }
131

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

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

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

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

    
169
    }
170

    
171
    /*
172
     * @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)
173
     */
174
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintRequestAttributeSet properties) throws ReadException {
175
        if (isVisible() && isWithinScale(scale)){
176
            drawGraphics(null, g, viewPort, cancel);
177
            }
178
    }
179

    
180
    /**
181
     * <p>Draws each graphic item of this layer that it's associated symbol is also in this layer, and its
182
     *  geometry intersects with the extent currently covered by the view (of the {@link ViewPort ViewPort}). If
183
     *  the graphic item is selected, will also draw its selection handlers.</p>
184
     *
185
     * @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.
186
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
187
         * @param viewPort the information for drawing the layers
188
         * @param cancel an object thread that implements the {@link Cancellable Cancellable} interface, and will allow to cancel the draw
189
         *
190
     * @see #draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
191
     * @see #print(Graphics2D, ViewPort, Cancellable, double, PrintRequestAttributeSet)
192
     */
193
    private void drawGraphics(BufferedImage image, Graphics2D g,
194
            ViewPort viewPort, Cancellable cancel)
195
    {
196
        int numReg;
197
        Rectangle2D elExtent = viewPort.getAdjustedExtent();
198
        if (elExtent == null) return;
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.getMinX(),
224
                        elExtent.getMinY(), elExtent.getWidth(), elExtent.getHeight()))
225
             {
226
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
227
                if (theSymbol == null)
228
                        continue;
229
                if (selection.get(numReg)) // Si est? seleccinado
230
                {
231
                        FGraphicUtilities.DrawHandlers(g, viewPort.getAffineTransform(), geom.getHandlers(Geometry.SELECTHANDLER), theSymbol);
232
                }
233
                else
234
                {
235
                        theGraphic.draw(g, viewPort, theSymbol);
236
                }
237
            }
238
        }
239
    }
240

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

    
256
    }
257

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

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

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

    
283
    }
284

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

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

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

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

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

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

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

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

    
388
        }
389

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

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

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

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

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

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

    
470
        }
471

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

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