Statistics
| Revision:

svn-gvsig-desktop / tags / J2ME_compat_v1_2_Build_1209 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / layers / GraphicLayer.java @ 19509

History | View | Annotate | Download (16.3 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.hardcode.gdbms.driver.exceptions.ReadDriverException;
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.symbols.ISymbol;
60
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
61
import com.iver.cit.gvsig.fmap.rendering.FGraphic;
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
 * <p>The class <code>GraphicLayer</code> represents a layer with graphical items, that are geometries with
68
 *  a symbol and handlers associated.</p>
69
 *
70
 * <p>The internal graphical items are independent to each other and can be selected separately. There is a bit set to
71
 * define which item are selected. And they which are selected, will be drawn with handlers, that according to the particular
72
 * implementation of each one, can allow to move, center, ... the graphic item.</p>
73
 *
74
 * @see FLyrDefault
75
 */
76
public class GraphicLayer extends FLyrDefault {
77
        /**
78
         * Internal list with all graphic items of this layer.
79
         *
80
         * @see #addGraphic(FGraphic)
81
         * @see #clearAllGraphics()
82
         * @see #getGraphic(int)
83
         * @see #getGraphicByObjectTag(Object)
84
         * @see #inserGraphics(int, Collection)
85
         * @see #insertGraphic(int, FGraphic)
86
         * @see #removeGraphic(FGraphic)
87
         * @see #removeGraphic(int)
88
         * @see #getNumGraphics()
89
         */
90
    private ArrayList graphics = new ArrayList();
91

    
92
        /**
93
         * Internal list with all symbols of this layer.
94
         *
95
         * @see #addSymbol(ISymbol)
96
         * @see #clearSymbolsGraphics()
97
         */
98
    private ArrayList symbols = new ArrayList();
99
    /**
100
         * Describes a rectangle defined by a location (x, y) and dimension, that represents this layer position
101
         *  and dimension.
102
         *
103
         * @see #getFullExtent()
104
         * @see #reCalculateFullExtent()
105
         */
106
    private Rectangle2D fullExtent;
107

    
108
        /**
109
         * An optimal index according a quadtree for fast access to spatial data.
110
         */
111
    private SpatialIndex spatialIndex = new Quadtree();
112
    /**
113
         * A set of boolean items that specifies which graphic items of this layer are selected.
114
         *
115
         * @see #getSelection()
116
         * @see #setSelection(FBitSet)
117
         */
118
    private FBitSet selection = new FBitSet();
119
    /**
120
         * Creates a default <i>FMap</i> layer.
121
         *
122
         * @see FLyrDefault#FLyrDefault()
123
         */
124
    public GraphicLayer() {
125
        super();
126
    }
127

    
128
    /*
129
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#getFullExtent()
130
     */
131
    public Rectangle2D getFullExtent() {
132
        return fullExtent;
133
    }
134

    
135

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

    
145
    /**
146
     * <p>Processes all graphic items of this layer according to the <i>visitor pattern</i>. This
147
     *  operation can be cancelled at any time.</p>
148
     *
149
     * @param visitor object that allows visit each graphic item
150
     * @param cancel an object thread that implements the {@link Cancellable Cancellable} interface, and allows
151
     *  cancel the visit
152
     */
153
    public void process(ItemVisitor visitor, Cancellable cancel)
154
    {
155
        int numReg;
156

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

    
167
    }
168

    
169

    
170
    /*
171
     * @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)
172
     */
173
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintRequestAttributeSet properties) throws ReadDriverException {
174
        if (isVisible() && isWithinScale(scale)){
175
            drawGraphics(null, g, viewPort, cancel);
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, PrintRequestAttributeSet)
190
     */
191
    private void drawGraphics(BufferedImage image, Graphics2D g,
192
            ViewPort viewPort, Cancellable cancel)
193
    {
194
        int numReg;
195
        Rectangle2D elExtent = viewPort.getAdjustedExtent();
196
        if (elExtent == null) return;
197

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

    
205
        ICoordTrans ct = getCoordTrans();
206

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

    
212
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
213
            IGeometry geom = theGraphic.getGeom();
214

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

    
221
            if (geom.fastIntersects(elExtent.getMinX(),
222
                        elExtent.getMinY(), elExtent.getWidth(), elExtent.getHeight()))
223
             {
224
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
225
                if (theSymbol == null)
226
                        continue;
227
                if (selection.get(numReg)) // Si est? seleccinado
228
                {
229
                        FGraphicUtilities.DrawHandlers(g, viewPort.getAffineTransform(), geom.getHandlers(IGeometry.SELECTHANDLER), theSymbol);
230
                }
231
                else
232
                {
233
                        theGraphic.draw(g, viewPort, theSymbol);
234
                }
235
            }
236
        }
237
    }
238
    /**
239
     * <p>Adds a new symbol to the graphic layer, and if success, returns the last index of the internal
240
     *  list of symbols.</p>
241
     *
242
     * @param newSymbol the new symbol
243
     * @return last index of the internal list of symbols if success, -1 otherwise
244
     *
245
     * @see #clearSymbolsGraphics()
246
     */
247
    public int addSymbol(ISymbol newSymbol)
248
    {
249
        if (symbols.add(newSymbol))
250
            return symbols.size()-1;
251
        return -1;
252

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

    
268
//                spatialIndex.insert(g.getGeom().getBounds2D())
269
            if (fullExtent == null) {
270
                fullExtent = g.getGeom().getBounds2D();
271
            } else {
272
                fullExtent.add(g.getGeom().getBounds2D());
273
            }
274

    
275
//            return graphics.size()-1;
276
        }
277
//        return -1;
278

    
279
    }
280
    /**
281
     * <p>Adds a new graphic item to the graphic layer at the position specified of the internal list, and if success,
282
     *  sets as new extent the graphic's one if this layer hadn't, otherwise sets as new extent the union of both.</p>
283
     *
284
     * @param position the index of the element to insert
285
     * @param g the new graphic item
286
     *
287
     * @see #inserGraphics(int, Collection)
288
     * @see #addGraphic(FGraphic)
289
     */
290
    public void insertGraphic(int position, FGraphic g) {
291
            graphics.add(position, g);
292
        if (fullExtent == null) {
293
            fullExtent = g.getGeom().getBounds2D();
294
        } else {
295
            fullExtent.add(g.getGeom().getBounds2D());
296
        }
297
    }
298
    /**
299
     * Removes all graphic items from this layer. The internal list of graphic items will be empty
300
     *  after this call returns, and layer won't have extent.
301
     *
302
     * @see #removeGraphic(FGraphic)
303
     * @see #removeGraphic(int)
304
     */
305
    public void clearAllGraphics()
306
    {
307
        graphics.clear();
308
        fullExtent = null;
309
    }
310
    /**
311
     * Removes all symbols from this layer. The internal list of symbols will be empty
312
     *  after this call returns.
313
     *
314
     * @see #addSymbol(ISymbol)
315
     */
316
    public void clearSymbolsGraphics()
317
    {
318
        symbols.clear();
319
    }
320
    /**
321
     * <p>Gets a set of boolean values that specifies which graphic items of this layer are selected.</p>
322
     *
323
     * @return a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item
324
     *  that has the same position in the internal list of graphic items of this layer, and to <code>false</code> if isn't selected
325
     *
326
     * @see #setSelection(FBitSet)
327
     */
328
        public FBitSet getSelection() {
329
                return selection;
330
        }
331

    
332
        /**
333
     * <p>Sets a set of boolean values that specifies which graphic items of this layer are selected.</p>
334
     *
335
     * @param selection a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item
336
     *  that has the same position in the internal list of graphic items of this layer, and to <code>false</code> if isn't selected
337
     *
338
     * @see #getSelection()
339
         */
340
        public void setSelection(FBitSet selection) {
341
                this.selection = selection;
342
        }
343
        /**
344
         * Returns a bit set that reports which graphic items that are geometries, intersect with
345
         *  the rectangle <code>r</code>.
346
         *
347
         * @param r the <code>Rectangle2D</code> to be intersected with all geometries of this layer
348
         * @return a <code>FBitSet</code> which <code>true</code> bits represent the geometries of this layer
349
         *  that intersect with the rectangle
350
         *
351
         * @see IGeometry#intersects(Rectangle2D)
352
         */
353
        public FBitSet queryByRect(Rectangle2D r) {
354
                FBitSet newSel = new FBitSet();
355
        for (int numReg = 0; numReg < graphics.size(); numReg++) {
356

    
357
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
358
            IGeometry geom = theGraphic.getGeom();
359
            if (geom.intersects(r))
360
            {
361
                    newSel.set(numReg);
362
            }
363
        }
364
        return newSel;
365
        }
366
        /**
367
         * Removes a graphic item and recalculates the extent of this layer.
368
         *
369
         * @param graphic the graphic item to be removed
370
         *
371
         * @see #removeGraphic(int)
372
         * @see #clearAllGraphics()
373
         */
374
        public void removeGraphic(FGraphic graphic) {
375
                graphics.remove(graphic);
376
                reCalculateFullExtent();
377

    
378
        }
379
        /**
380
         * Returns the item at the specified position in the internal list of graphics.
381
         *
382
         * @param idGraphic index of item to return
383
         * @return the item at the specified position in the internal list of graphics
384
         *
385
         * @see #getGraphicByObjectTag(Object)
386
         * @see #getNumGraphics()
387
         */
388
        public FGraphic getGraphic(int idGraphic) {
389
                return (FGraphic) graphics.get(idGraphic);
390
        }
391
        /**
392
         * Returns the graphic item of this layer, that has the specified object tag.
393
         *
394
         * @param objectTag the object tag of the item to return
395
         * @return the item that has the specified object tag, or <code>null</code> if there was no item that had it
396
         *
397
         * @see #getGraphic(int)
398
         * @see #getNumGraphics()
399
         */
400
        public FGraphic getGraphicByObjectTag(Object objectTag) {
401
        for (int i = 0; i < graphics.size(); i++) {
402
             FGraphic theGraphic = (FGraphic) graphics.get(i);
403
             if (theGraphic.getObjectTag() == objectTag)
404
                     return theGraphic;
405
         }
406
        return null;
407
        }
408

    
409
        /**
410
         * Returns the number of graphic items in this layer.
411
         *
412
         * @return the number of graphic items in this list
413
         *
414
         * @see #addGraphic(FGraphic)
415
         * @see #inserGraphics(int, Collection)
416
         * @see #insertGraphic(int, FGraphic)
417
         * @see #clearAllGraphics()
418
         * @see #removeGraphic(FGraphic)
419
         * @see #removeGraphic(int)
420
         * @see #getGraphic(int)
421
         */
422
        public int getNumGraphics() {
423
                return graphics.size();
424
        }
425
        /**
426
         * Recalculates the full extent of this layer as the union of the bounds 2D
427
         *  of all internal graphic items.
428
         */
429
        private void reCalculateFullExtent(){
430
                if (graphics.size() > 0) {
431
                        FGraphic g = (FGraphic) graphics.get(0);
432
                        fullExtent = g.getGeom().getBounds2D();
433
                        for (int i = 1; i < graphics.size(); i++) {
434
                                g = (FGraphic) graphics.get(i);
435
                                Rectangle2D rAux = g.getGeom().getBounds2D();
436

    
437
                                fullExtent.add(rAux);
438
                        }
439
                }
440
        }
441
        /**
442
         * <p>Inserts all of the elements in the specified {@link Collection Collection} into the internal list of graphic items,
443
         *  starting at the specified position. Shifts the element currently at that position (if any) and any
444
         *  subsequent elements to the right (increases their indices). The new elements will appear in the list
445
         *  in the order that they are returned by the specified collection's iterator.</p>
446
         *
447
         * @param index index at which to insert first element from the specified collection
448
         * @param c elements to be inserted into this list
449
         *
450
         * @see #insertGraphic(int, FGraphic)
451
         * @see #addGraphic(FGraphic)
452
         */
453
        public void inserGraphics(int index, Collection c) {
454
                graphics.addAll(index, c);
455

    
456
        }
457

    
458
        /**
459
         * <p>Fast remove: removes only a graphic item of this layer.</p>
460
         * <p>Remember to call {@linkplain #reCalculateFullExtent()} when you finish removing graphics.</p>
461
         *
462
         * @param graphicIndex the graphic item to be removed
463
         *
464
         * @see #removeGraphic(FGraphic)
465
         * @see #clearAllGraphics()
466
         */
467
        public void removeGraphic(int graphicIndex) {
468
                graphics.remove(graphicIndex);
469
        }
470
        /**
471
          * Return index of symbol, if it exists.
472
          * @param sym
473
          * @return -1 if it is not inside the symbols list.
474
          */
475
        public int getSymbol(ISymbol sym) {
476
                if (symbols.contains(sym)) {
477
                        return symbols.indexOf(sym);
478
                }
479
                return -1;
480
        }
481
}