Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / layers / GraphicLayer.java @ 25274

History | View | Annotate | Download (16 KB)

1 2901 fjp
/*
2
 * Created on 19-sep-2005
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5 8142 jaume
 *
6 2901 fjp
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7 8142 jaume
 *
8 2901 fjp
 * 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 8142 jaume
 *
13 2901 fjp
 * 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 8142 jaume
 *
18 2901 fjp
 * 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 8142 jaume
 *
22 2901 fjp
 * 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 8142 jaume
 *
34 2901 fjp
 *    or
35 8142 jaume
 *
36 2901 fjp
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40 8142 jaume
 *
41 2901 fjp
 *   +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 8760 fjp
import java.util.Collection;
51 2901 fjp
52 9010 caballero
import javax.print.attribute.PrintRequestAttributeSet;
53
54 4479 fjp
import org.cresques.cts.ICoordTrans;
55
56 10627 caballero
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
57 2901 fjp
import com.iver.cit.gvsig.fmap.ViewPort;
58 2974 fjp
import com.iver.cit.gvsig.fmap.core.IGeometry;
59 9641 jaume
import com.iver.cit.gvsig.fmap.core.symbols.ISymbol;
60 6945 fjp
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
61 2901 fjp
import com.iver.cit.gvsig.fmap.rendering.FGraphic;
62 5317 fjp
import com.iver.utiles.swing.threads.Cancellable;
63 6945 fjp
import com.vividsolutions.jts.index.ItemVisitor;
64
import com.vividsolutions.jts.index.SpatialIndex;
65
import com.vividsolutions.jts.index.quadtree.Quadtree;
66 20098 jmvivo
67 14295 jvidal
/**
68 20098 jmvivo
 * <p><code>GraphicLayer</code> represents a layer with graphical items, that are geometries with
69 14295 jvidal
 *  a symbol and handlers associated.</p>
70 20098 jmvivo
 *
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 14295 jvidal
 * @see FLyrDefault
76
 */
77 2901 fjp
public class GraphicLayer extends FLyrDefault {
78 14295 jvidal
        /**
79
         * Internal list with all graphic items of this layer.
80 20098 jmvivo
         *
81 14295 jvidal
         * @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 2901 fjp
    private ArrayList graphics = new ArrayList();
92 14295 jvidal
93
        /**
94
         * Internal list with all symbols of this layer.
95 20098 jmvivo
         *
96 14295 jvidal
         * @see #addSymbol(ISymbol)
97
         * @see #clearSymbolsGraphics()
98
         */
99 2901 fjp
    private ArrayList symbols = new ArrayList();
100 20098 jmvivo
101
        /**
102 14295 jvidal
         * Describes a rectangle defined by a location (x, y) and dimension, that represents this layer position
103
         *  and dimension.
104 20098 jmvivo
         *
105 14295 jvidal
         * @see #getFullExtent()
106
         * @see #reCalculateFullExtent()
107
         */
108 2901 fjp
    private Rectangle2D fullExtent;
109 14295 jvidal
110
        /**
111
         * An optimal index according a quadtree for fast access to spatial data.
112
         */
113 6945 fjp
    private SpatialIndex spatialIndex = new Quadtree();
114 20098 jmvivo
115
        /**
116 14295 jvidal
         * A set of boolean items that specifies which graphic items of this layer are selected.
117 20098 jmvivo
         *
118 14295 jvidal
         * @see #getSelection()
119
         * @see #setSelection(FBitSet)
120
         */
121 6945 fjp
    private FBitSet selection = new FBitSet();
122 20098 jmvivo
123
        /**
124
         * <p>Creates a new <code>GraphicLayer</code> instance.</p>
125
         *
126 14295 jvidal
         * @see FLyrDefault#FLyrDefault()
127
         */
128 2901 fjp
    public GraphicLayer() {
129
        super();
130
    }
131
132 14295 jvidal
    /*
133 2901 fjp
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#getFullExtent()
134
     */
135 10627 caballero
    public Rectangle2D getFullExtent() {
136 2901 fjp
        return fullExtent;
137
    }
138
139 14295 jvidal
    /*
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 2901 fjp
     */
142 10627 caballero
    public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale) throws ReadDriverException {
143 8142 jaume
        if (isVisible() && isWithinScale(scale)){
144 2901 fjp
            drawGraphics(image, g, viewPort, cancel);
145 8142 jaume
            }
146 2901 fjp
    }
147 8142 jaume
148 6945 fjp
    /**
149 14295 jvidal
     * <p>Processes all graphic items of this layer according to the <i>visitor pattern</i>. This
150 20098 jmvivo
     *  operation can be canceled at any time.</p>
151
     *
152 14295 jvidal
     * @param visitor object that allows visit each graphic item
153 20098 jmvivo
     * @param cancel shared object that determines if this layer can continue being drawn
154 6945 fjp
     */
155
    public void process(ItemVisitor visitor, Cancellable cancel)
156
    {
157
        int numReg;
158 8142 jaume
159 6945 fjp
        for (numReg = 0; numReg < graphics.size(); numReg++) {
160 8511 azabala
           if(cancel != null){
161
                        if (cancel.isCanceled()) {
162
                        break;
163
                    }
164 6945 fjp
            }
165
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
166
            visitor.visitItem(theGraphic);
167
        }
168 8142 jaume
169 6945 fjp
    }
170 2901 fjp
171 14295 jvidal
    /*
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 2901 fjp
     */
174 10627 caballero
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintRequestAttributeSet properties) throws ReadDriverException {
175 8142 jaume
        if (isVisible() && isWithinScale(scale)){
176 2901 fjp
            drawGraphics(null, g, viewPort, cancel);
177 8142 jaume
            }
178 2901 fjp
    }
179 20098 jmvivo
180 14295 jvidal
    /**
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 20098 jmvivo
     *  the graphic item is selected, will also draw its selection handlers.</p>
184
     *
185 14295 jvidal
     * @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 20098 jmvivo
         *
190 14295 jvidal
     * @see #draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
191
     * @see #print(Graphics2D, ViewPort, Cancellable, double, PrintRequestAttributeSet)
192
     */
193 2901 fjp
    private void drawGraphics(BufferedImage image, Graphics2D g,
194 8142 jaume
            ViewPort viewPort, Cancellable cancel)
195 2901 fjp
    {
196
        int numReg;
197 2974 fjp
        Rectangle2D elExtent = viewPort.getAdjustedExtent();
198 2901 fjp
        if (elExtent == null) return;
199 8142 jaume
200 2901 fjp
        //int anchoMapa;
201
        //int altoMapa;
202
        //double anchoReal;
203
        //double altoReal;
204
        //double escala;
205 8142 jaume
        ISymbol theSymbol = null;
206
207 4479 fjp
        ICoordTrans ct = getCoordTrans();
208 8142 jaume
209 2901 fjp
        for (numReg = 0; numReg < graphics.size(); numReg++) {
210
            if (cancel.isCanceled()) {
211
                break;
212
            }
213 8142 jaume
214 2901 fjp
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
215 2974 fjp
            IGeometry geom = theGraphic.getGeom();
216 8142 jaume
217 4479 fjp
            // 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 8142 jaume
223
            if (geom.fastIntersects(elExtent.getMinX(),
224 2901 fjp
                        elExtent.getMinY(), elExtent.getWidth(), elExtent.getHeight()))
225
             {
226 8142 jaume
                theSymbol = (ISymbol) symbols.get(theGraphic.getIdSymbol());
227 8595 fjp
                if (theSymbol == null)
228
                        continue;
229 6945 fjp
                if (selection.get(numReg)) // Si est? seleccinado
230
                {
231 11434 caballero
                        FGraphicUtilities.DrawHandlers(g, viewPort.getAffineTransform(), geom.getHandlers(IGeometry.SELECTHANDLER), theSymbol);
232 6945 fjp
                }
233
                else
234
                {
235
                        theGraphic.draw(g, viewPort, theSymbol);
236
                }
237 2901 fjp
            }
238
        }
239 8142 jaume
    }
240 20098 jmvivo
241 14295 jvidal
    /**
242 20098 jmvivo
     * <p>Adds a new symbol to the graphic layer, and, if success, returns the last index of the internal
243 14295 jvidal
     *  list of symbols.</p>
244 20098 jmvivo
     *
245 14295 jvidal
     * @param newSymbol the new symbol
246
     * @return last index of the internal list of symbols if success, -1 otherwise
247 20098 jmvivo
     *
248 14295 jvidal
     * @see #clearSymbolsGraphics()
249
     */
250 8142 jaume
    public int addSymbol(ISymbol newSymbol)
251
    {
252 2901 fjp
        if (symbols.add(newSymbol))
253
            return symbols.size()-1;
254
        return -1;
255 8142 jaume
256 2901 fjp
    }
257 20098 jmvivo
258 2970 fjp
    /**
259 20098 jmvivo
     * <p>Adds a new graphic item to the graphic layer, and, if success, sets as new extent the graphic's
260 14295 jvidal
     *  one if this layer hadn't, otherwise sets as new extent the union of both.</p>
261 20098 jmvivo
     *
262 14295 jvidal
     * @param g the new graphic item
263 20098 jmvivo
     *
264 14295 jvidal
     * @see #insertGraphic(int, FGraphic)
265
     * @see #inserGraphics(int, Collection)
266 2970 fjp
     */
267 8208 fjp
    public void addGraphic(FGraphic g)
268 2901 fjp
    {
269
        if (graphics.add(g))
270
        {
271 8142 jaume
272 6945 fjp
//                spatialIndex.insert(g.getGeom().getBounds2D())
273 2901 fjp
            if (fullExtent == null) {
274
                fullExtent = g.getGeom().getBounds2D();
275
            } else {
276
                fullExtent.add(g.getGeom().getBounds2D());
277
            }
278
279 8208 fjp
//            return graphics.size()-1;
280 2901 fjp
        }
281 8208 fjp
//        return -1;
282 2901 fjp
283
    }
284 20098 jmvivo
285 14295 jvidal
    /**
286 20098 jmvivo
     * <p>Adds a new graphic item to the graphic layer at the position specified of the internal list, and, if success,
287 14295 jvidal
     *  sets as new extent the graphic's one if this layer hadn't, otherwise sets as new extent the union of both.</p>
288 20098 jmvivo
     *
289
     * @param position the index of the element to insert
290 14295 jvidal
     * @param g the new graphic item
291 20098 jmvivo
     *
292 14295 jvidal
     * @see #inserGraphics(int, Collection)
293
     * @see #addGraphic(FGraphic)
294
     */
295 8208 fjp
    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 20098 jmvivo
304 2970 fjp
    /**
305 14295 jvidal
     * 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 20098 jmvivo
     *
308 14295 jvidal
     * @see #removeGraphic(FGraphic)
309
     * @see #removeGraphic(int)
310 2970 fjp
     */
311 2901 fjp
    public void clearAllGraphics()
312
    {
313
        graphics.clear();
314 8327 fjp
        fullExtent = null;
315 2901 fjp
    }
316 20098 jmvivo
317 2970 fjp
    /**
318 14295 jvidal
     * Removes all symbols from this layer. The internal list of symbols will be empty
319
     *  after this call returns.
320 20098 jmvivo
     *
321 14295 jvidal
     * @see #addSymbol(ISymbol)
322 2970 fjp
     */
323 2901 fjp
    public void clearSymbolsGraphics()
324
    {
325
        symbols.clear();
326
    }
327 20098 jmvivo
328 14295 jvidal
    /**
329
     * <p>Gets a set of boolean values that specifies which graphic items of this layer are selected.</p>
330 20098 jmvivo
     *
331
     * @return a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item
332 14295 jvidal
     *  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 20098 jmvivo
     *
334 14295 jvidal
     * @see #setSelection(FBitSet)
335
     */
336 6945 fjp
        public FBitSet getSelection() {
337
                return selection;
338
        }
339
340 14295 jvidal
        /**
341
     * <p>Sets a set of boolean values that specifies which graphic items of this layer are selected.</p>
342 20098 jmvivo
     *
343
     * @param selection a set of boolean values. Each value is equal to <code>true</code> if is selected the graphic item
344 14295 jvidal
     *  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 20098 jmvivo
     *
346 14295 jvidal
     * @see #getSelection()
347
         */
348 6945 fjp
        public void setSelection(FBitSet selection) {
349
                this.selection = selection;
350
        }
351 20098 jmvivo
352 14295 jvidal
        /**
353 20098 jmvivo
         * Returns a bit set that reports which graphic items <i>(geometries)</i>, intersect with
354 14295 jvidal
         *  the rectangle <code>r</code>.
355 20098 jmvivo
         *
356
         * @param r the <code>Rectangle2D</code> to be intersected with some geometries of this layer
357 14295 jvidal
         * @return a <code>FBitSet</code> which <code>true</code> bits represent the geometries of this layer
358
         *  that intersect with the rectangle
359 20098 jmvivo
         *
360 14295 jvidal
         * @see IGeometry#intersects(Rectangle2D)
361
         */
362 6945 fjp
        public FBitSet queryByRect(Rectangle2D r) {
363
                FBitSet newSel = new FBitSet();
364
        for (int numReg = 0; numReg < graphics.size(); numReg++) {
365 8142 jaume
366 6945 fjp
            FGraphic theGraphic = (FGraphic) graphics.get(numReg);
367
            IGeometry geom = theGraphic.getGeom();
368
            if (geom.intersects(r))
369
            {
370
                    newSel.set(numReg);
371
            }
372
        }
373
        return newSel;
374
        }
375 20098 jmvivo
376 14295 jvidal
        /**
377
         * Removes a graphic item and recalculates the extent of this layer.
378 20098 jmvivo
         *
379 14295 jvidal
         * @param graphic the graphic item to be removed
380 20098 jmvivo
         *
381 14295 jvidal
         * @see #removeGraphic(int)
382
         * @see #clearAllGraphics()
383
         */
384 8616 fjp
        public void removeGraphic(FGraphic graphic) {
385 8327 fjp
                graphics.remove(graphic);
386
                reCalculateFullExtent();
387 9010 caballero
388 8327 fjp
        }
389 20098 jmvivo
390 14295 jvidal
        /**
391
         * Returns the item at the specified position in the internal list of graphics.
392 20098 jmvivo
         *
393 14295 jvidal
         * @param idGraphic index of item to return
394
         * @return the item at the specified position in the internal list of graphics
395 20098 jmvivo
         *
396 14295 jvidal
         * @see #getGraphicByObjectTag(Object)
397
         * @see #getNumGraphics()
398
         */
399 8575 fjp
        public FGraphic getGraphic(int idGraphic) {
400
                return (FGraphic) graphics.get(idGraphic);
401
        }
402 20098 jmvivo
403 14295 jvidal
        /**
404
         * Returns the graphic item of this layer, that has the specified object tag.
405 20098 jmvivo
         *
406
         * @param objectTag the tag of the item to return
407 14295 jvidal
         * @return the item that has the specified object tag, or <code>null</code> if there was no item that had it
408 20098 jmvivo
         *
409 14295 jvidal
         * @see #getGraphic(int)
410
         * @see #getNumGraphics()
411
         */
412 8616 fjp
        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 14295 jvidal
        /**
422
         * Returns the number of graphic items in this layer.
423
         *
424
         * @return the number of graphic items in this list
425 20098 jmvivo
         *
426 14295 jvidal
         * @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 8575 fjp
        public int getNumGraphics() {
435
                return graphics.size();
436
        }
437 20098 jmvivo
438 14295 jvidal
        /**
439
         * Recalculates the full extent of this layer as the union of the bounds 2D
440
         *  of all internal graphic items.
441
         */
442 8327 fjp
        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 20098 jmvivo
455 14295 jvidal
        /**
456
         * <p>Inserts all of the elements in the specified {@link Collection Collection} into the internal list of graphic items,
457 20098 jmvivo
         *  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 14295 jvidal
         *  in the order that they are returned by the specified collection's iterator.</p>
460 20098 jmvivo
         *
461
         * @param index index where starting to insert the elements from the specified collection
462 14295 jvidal
         * @param c elements to be inserted into this list
463 20098 jmvivo
         *
464 14295 jvidal
         * @see #insertGraphic(int, FGraphic)
465
         * @see #addGraphic(FGraphic)
466
         */
467 8760 fjp
        public void inserGraphics(int index, Collection c) {
468
                graphics.addAll(index, c);
469 9010 caballero
470 8760 fjp
        }
471
472 13664 fjp
        /**
473 14295 jvidal
         * <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 20098 jmvivo
         *
476 14295 jvidal
         * @param graphicIndex the graphic item to be removed
477 20098 jmvivo
         *
478 14295 jvidal
         * @see #removeGraphic(FGraphic)
479
         * @see #clearAllGraphics()
480 13664 fjp
         */
481
        public void removeGraphic(int graphicIndex) {
482
                graphics.remove(graphicIndex);
483
        }
484 20098 jmvivo
485 14778 vcaballero
        /**
486 20098 jmvivo
          * <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 14778 vcaballero
          */
491
        public int getSymbol(ISymbol sym) {
492
                if (symbols.contains(sym)) {
493
                        return symbols.indexOf(sym);
494
                }
495
                return -1;
496
        }
497 2901 fjp
}