Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / operations / strategies / AnnotationStrategy.java @ 4523

History | View | Annotate | Download (17.2 KB)

1
package com.iver.cit.gvsig.fmap.operations.strategies;
2

    
3
import java.awt.FontMetrics;
4
import java.awt.Graphics2D;
5
import java.awt.geom.AffineTransform;
6
import java.awt.geom.Point2D;
7
import java.awt.geom.Rectangle2D;
8
import java.awt.image.BufferedImage;
9
import java.io.IOException;
10
import java.util.BitSet;
11
import java.util.List;
12

    
13
import org.apache.log4j.Logger;
14
import org.cresques.cts.ICoordTrans;
15
import org.geotools.resources.geometry.XRectangle2D;
16

    
17
import com.iver.cit.gvsig.fmap.DriverException;
18
import com.iver.cit.gvsig.fmap.ViewPort;
19
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
20
import com.iver.cit.gvsig.fmap.core.IGeometry;
21
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
22
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
23
import com.iver.cit.gvsig.fmap.core.v02.FLabel;
24
import com.iver.cit.gvsig.fmap.core.v02.FSymbol;
25
import com.iver.cit.gvsig.fmap.drivers.BoundedShapes;
26
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
27
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
28
import com.iver.cit.gvsig.fmap.drivers.VectorialFileDriver;
29
import com.iver.cit.gvsig.fmap.layers.FBitSet;
30
import com.iver.cit.gvsig.fmap.layers.FLayer;
31
import com.iver.cit.gvsig.fmap.layers.FLyrAnnotation;
32
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
33
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
34
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
35
import com.iver.cit.gvsig.fmap.layers.layerOperations.ClassifiableVectorial;
36
import com.iver.cit.gvsig.fmap.layers.layerOperations.Selectable;
37
import com.iver.cit.gvsig.fmap.layers.layerOperations.SingleLayer;
38
import com.iver.cit.gvsig.fmap.operations.Cancellable;
39
import com.iver.cit.gvsig.fmap.rendering.VectorialLegend;
40
import com.iver.cit.gvsig.fmap.rendering.styling.FStyle2D;
41
import com.vividsolutions.jts.geom.Coordinate;
42
import com.vividsolutions.jts.geom.Envelope;
43
import com.vividsolutions.jts.geom.Geometry;
44
import com.vividsolutions.jts.geom.IntersectionMatrix;
45

    
46

    
47
/**
48
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
49
 * anotaciones.
50
 *
51
 * @author Vicente Caballero Navarro
52
 */
53
public class AnnotationStrategy extends DefaultStrategy {
54
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
55
        //private FLyrAnnotation la;
56
        //private ArrayList m_labels;
57

    
58

    
59
        /**
60
     * Crea un nuevo AnotationStrategy.
61
     *
62
     * @param layer DOCUMENT ME!
63
     */
64
    public AnnotationStrategy(FLayer layer) {
65
        super(layer);
66
        capa = (FLyrAnnotation) layer;
67
    }
68
    /**
69
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
70
         *                 java.awt.Graphics2D, FStyle2D)
71
         */
72
        public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
73
                Cancellable cancel) throws DriverException {
74
                int numReg;
75
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
76
                VectorialLegend l=(VectorialLegend)lyrAnnotation.getLegend();
77
                FBitSet bitSet=lyrAnnotation.getRecordset().getSelection();
78
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
79
                boolean inPixels=lyrAnnotation.isInPixels();
80
                FSymbol theSymbol = l.getDefaultSymbol();
81
                theSymbol.setFontSizeInPixels(inPixels);
82
                System.out.println("Dibujando Anotaciones...");
83
                ViewPort vp=viewPort;//capa.getFMap().getViewPort();
84
                AffineTransform at=vp.getAffineTransform();
85
                try {
86
                long numRows=lyrAnnotation.getRecordset().getRowCount();
87
                FontMetrics metrics = g.getFontMetrics();
88
                        for (numReg = 0; numReg < numRows; numReg++) {
89
                                if (cancel.isCanceled()) {
90
                                        break;
91
                                }
92
                                FLabel theLabel = (FLabel) ((FLyrAnnotation) capa).getLabel(numReg);
93
                                if ((theLabel == null) || (theLabel.getOrig() == null))
94
                                        continue;
95

    
96
                                Rectangle2D r=getBoundBox(theLabel.getOrig(), g,(float)theLabel.getHeight(), theLabel.getJustification(),vp,theLabel.getString());
97
                                theLabel.setBoundBox(r);
98
                                if (elExtent.intersects(r)) {
99
                                        if (bitSet.get(numReg)) {
100
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,true);
101
                                        }else{
102
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,false);
103
                                        }
104
                                }
105
                        }
106
                } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
107
                        e.printStackTrace();
108
                }
109
        }
110
         /**
111
     * Construcci?n del rect?ngulo
112
     *
113
     * @param p
114
     * @param g DOCUMENT ME!
115
     * @param justification DOCUMENT ME!
116
     * @param vp DOCUMENT ME!
117
     *
118
     * @return
119
     */
120
    public Rectangle2D getBoundBox(Point2D p, Graphics2D g,float hp,
121
        int justification, ViewPort vp,String s) {
122
        Rectangle2D bounding=null;
123
        if (((FLyrAnnotation)capa).isInPixels()){
124
                g.setFont(g.getFont().deriveFont(hp));
125
        }else{
126
                float alturaPixels = (float) ((hp * vp.getAffineTransform().getScaleX())*FLabel.SQUARE);
127
                g.setFont(g.getFont().deriveFont(alturaPixels));
128
        }
129
        FontMetrics metrics = g.getFontMetrics();
130
        int w = metrics.stringWidth(s);
131
        double width = vp.toMapDistance(w);
132
        int h = metrics.getMaxAscent();
133
        double height = vp.toMapDistance(h);
134
        double dist = vp.toMapDistance(3);
135

    
136
        switch (justification) {
137
            case FLabel.LEFT_BOTTOM:
138
                bounding=justification(p, width,height, 0, -dist);
139

    
140
                break;
141

    
142
            case FLabel.LEFT_CENTER:
143
                     bounding=justification(p, width,height, 0, -(height / 2));
144

    
145
                break;
146

    
147
            case FLabel.LEFT_TOP:
148
                     bounding=justification(p,width,height, 0, -height);
149

    
150
                break;
151

    
152
            case FLabel.CENTER_BOTTOM:
153
                     bounding=justification(p, width,height, -(width / 2), -dist);
154

    
155
                break;
156

    
157
            case FLabel.CENTER_CENTER:
158
                     bounding=justification(p, width,height, -(width / 2), -(height / 2));
159

    
160
                break;
161

    
162
            case FLabel.CENTER_TOP:
163
                     bounding=justification(p, width,height, -(width / 2), -height);
164

    
165
                break;
166

    
167
            case FLabel.RIGHT_BOTTOM:
168
                     bounding=justification(p, width,height, -width, -dist);
169

    
170
                break;
171

    
172
            case FLabel.RIGHT_CENTER:
173
                     bounding=justification(p, width,height, -width, -(height / 2));
174

    
175
                break;
176

    
177
            case FLabel.RIGHT_TOP:
178
                     bounding=justification(p, width,height, -width, -height);
179

    
180
                break;
181
        }
182

    
183
        return bounding;
184
    }
185
    private Rectangle2D justification(Point2D p, double w,double h, double x, double y) {
186
        Rectangle2D r=new Rectangle2D.Double(p.getX() + x, p.getY() - y, w, h);
187
        return r;
188
    }
189
        /**
190
         * M?todo utilizado para dibujar sobre el graphics que se pasa como
191
         * par?metro, pensado para utilizarse para imprimir.
192
         *
193
         * @param g
194
         *            Graphics2D
195
         * @param viewPort
196
         *            ViewPort.
197
         * @param cancel
198
         *
199
         * @throws DriverException
200
         */
201
        public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel)
202
                throws DriverException {
203
                // super.draw(null, g, viewPort, cancel); // Quiero ejecutar el draw del padre, que es el que va sin acelaraci?n!!
204
        try {
205
            ReadableVectorial adapter = ((SingleLayer) getCapa()).getSource();
206
            if (adapter.getShapeCount() <= 0)
207
            {
208
                logger.debug("Layer:" + getCapa().getName() + " sin registros");
209
                return;
210
            }
211
            Selectable selection = (Selectable) getCapa();
212
            ICoordTrans ct = getCapa().getCoordTrans();
213
            BitSet bitSet = selection.getSelection();
214
            BoundedShapes shapeBounds = (BoundedShapes) adapter.getDriver();
215
            VectorialFileDriver driver = (VectorialFileDriver) adapter.getDriver();
216
            // logger.debug("adapter.start() -> Layer:" + getCapa().getName());
217
            adapter.start();
218
            IGeometry geom;
219
            if (adapter.getShapeCount()>0){
220
            geom = adapter.getShape(0);
221
            }
222
            VectorialLegend l = (VectorialLegend) ((ClassifiableVectorial) getCapa()).getLegend();
223

    
224
            Rectangle2D extent = viewPort.getAdjustedExtent();
225
            //AffineTransform at = viewPort.getAffineTransform();
226

    
227
            int sc;
228

    
229
            Rectangle2D bounds;
230

    
231
            sc = adapter.getShapeCount();
232

    
233
            long t1 = System.currentTimeMillis();
234
            // logger.debug("getCapa().getRecordset().start()");
235
            ((AlphanumericData) getCapa()).getRecordset().start();
236

    
237
            // TODO: A revisar si es o no conveniente este sistema
238
            // de comunicaci?n con los drivers.
239
            DriverAttributes attr = adapter.getDriverAttributes();
240
            boolean bMustClone = false;
241
            if (attr != null)
242
            {
243
                if (attr.isLoadedInMemory())
244
                {
245
                    bMustClone = attr.isLoadedInMemory();
246
                }
247
            }
248

    
249

    
250
            for (int i = 0; i < sc; i++) {
251

    
252
                bounds = shapeBounds.getShapeBounds(i);
253

    
254
                if (ct != null) {
255
                    bounds = ct.convert(bounds);
256
                }
257

    
258
                if (XRectangle2D.intersectInclusive(extent, bounds)) {
259
                    FSymbol symbol = l.getSymbol(i);
260

    
261
                    if (bitSet.get(i)) {
262
                        symbol = FSymbol.getSymbolForSelection(symbol);
263
                    }
264

    
265
                    geom = driver.getShape(i);
266

    
267
                    // PRUEBA DE VELOCIDAD
268
                    // geom = ShapeFactory.createPolygon2D(new GeneralPathX(bounds));
269

    
270
                    if (ct != null) {
271
                        if (bMustClone)
272
                            geom = geom.cloneGeometry();
273
                        geom.reProject(ct);
274
                    }
275
                    geom.draw(g, viewPort, symbol);
276
                }
277
            }
278

    
279
            // logger.debug("getCapa().getRecordset().stop()");
280
            ((AlphanumericData) getCapa()).getRecordset().stop();
281

    
282
            long t2 = System.currentTimeMillis();
283
            // logger.debug("adapter.stop()");
284
            adapter.stop();
285

    
286
            // System.out.println(t2 - t1);
287
        } catch (DriverIOException e) {
288
            throw new DriverException(e);
289
        } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
290
            throw new DriverException(e);
291
        } catch (DriverException e) {
292
            throw new DriverException(e);
293
        } catch (IOException e) {
294
            throw new DriverException(e);
295
        }
296

    
297
        }
298

    
299
    /* (non-Javadoc)
300
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.core.IGeometry, int)
301
     */
302
    public FBitSet queryByShape(IGeometry g, int relationship)
303
    throws DriverException, VisitException {
304
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
305
        FLyrVect lyr = (FLyrVect) capa;
306
        if (lyr.getSpatialIndex() == null)
307
            return super.queryByShape(g, relationship);
308

    
309
        long t1 = System.currentTimeMillis();
310
        ReadableVectorial va = lyr.getSource();
311
        ICoordTrans ct = lyr.getCoordTrans();
312
        Rectangle2D bounds = g.getBounds2D();
313
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
314
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
315
        Envelope env = new Envelope(c1, c2);
316

    
317
        List lstRecs = lyr.getSpatialIndex().query(env);
318
        Integer idRec;
319
        FBitSet bitset = new FBitSet();
320
        Geometry jtsShape = g.toJTSGeometry();
321
        IntersectionMatrix m;
322
        int index;
323
        try {
324
            va.start();
325

    
326
            for (int i=0; i < lstRecs.size(); i++)
327
            {
328
                idRec = (Integer) lstRecs.get(i);
329
                index = idRec.intValue();
330
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
331
                if (ct != null) {
332
                    geom.reProject(ct);
333
                }
334
                Geometry jtsGeom = geom.toJTSGeometry();
335
                switch (relationship) {
336
                case CONTAINS:
337
                    m = jtsShape.relate(jtsGeom);
338
                    if (m.isContains()) {
339
                        bitset.set(index, true);
340
                    }
341
                    break;
342

    
343
                case CROSSES:
344
                    m = jtsShape.relate(jtsGeom);
345
                    if (m.isCrosses(jtsGeom.getDimension(), jtsShape.getDimension())) {
346
                        bitset.set(index, true);
347
                    }
348
                    break;
349

    
350
                case DISJOINT:
351
                    // TODO: CREO QUE EL DISJOINT NO SE PUEDE METER AQUI
352
                    m = jtsShape.relate(jtsGeom);
353
                    if (m.isDisjoint()) {
354
                        bitset.set(index, true);
355
                    }
356
                    break;
357

    
358
                case EQUALS:
359
                    m = jtsShape.relate(jtsGeom);
360
                    if (m.isEquals(jtsGeom.getDimension(), jtsShape.getDimension())) {
361
                        bitset.set(index, true);
362
                    }
363
                    break;
364

    
365
                case INTERSECTS:
366
                    m = jtsShape.relate(jtsGeom);
367
                    if (m.isIntersects()) {
368
                        bitset.set(index, true);
369
                    }
370
                    break;
371

    
372
                case OVERLAPS:
373
                    m = jtsShape.relate(jtsGeom);
374
                    if (m.isOverlaps(jtsGeom.getDimension(), jtsShape.getDimension()))
375
                    {
376
                        bitset.set(index, true);
377
                    }
378

    
379
                    break;
380

    
381
                case TOUCHES:
382
                    m = jtsShape.relate(jtsGeom);
383
                    if (m.isTouches(jtsGeom.getDimension(), jtsShape.getDimension()))
384
                    {
385
                        bitset.set(index, true);
386
                    }
387

    
388
                    break;
389

    
390
                case WITHIN:
391
                    m = jtsShape.relate(jtsGeom);
392
                    if (m.isWithin()) {
393
                        bitset.set(index, true);
394
                    }
395

    
396
                    break;
397
                }
398
            }
399
            va.stop();
400
        } catch (DriverIOException e) {
401
            // TODO Auto-generated catch block
402
            e.printStackTrace();
403
        }
404
        long t2 = System.currentTimeMillis();
405
        logger.debug("queryByShape optimizado sobre la capa " + lyr.getName() + ". " + (t2-t1) + " mseg.");
406
        return bitset;
407
    }
408
    public FBitSet queryByRect(Rectangle2D rect) throws DriverException {
409
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
410
        FLyrAnnotation lyr = (FLyrAnnotation) capa;
411
        if (lyr.getSpatialIndex() == null)
412
            return super.queryByRect(rect);
413

    
414
        ReadableVectorial va = lyr.getSource();
415
        ICoordTrans ct = lyr.getCoordTrans();
416
        Rectangle2D bounds = rect;
417
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
418
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
419
        Envelope env = new Envelope(c1, c2);
420

    
421
        List lstRecs = lyr.getSpatialIndex().query(env);
422
        Integer idRec;
423
        FBitSet bitset = new FBitSet();
424
        int index;
425
        try {
426
            va.start();
427
            DriverAttributes attr = va.getDriverAttributes();
428
            boolean bMustClone = false;
429
            if (attr != null)
430
            {
431
                if (attr.isLoadedInMemory())
432
                {
433
                    bMustClone = attr.isLoadedInMemory();
434
                }
435
            }
436

    
437
            for (int i=0; i < lstRecs.size(); i++)
438
            {
439
                idRec = (Integer) lstRecs.get(i);
440
                index = idRec.intValue();
441
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
442
                if (ct != null) {
443
                    if (bMustClone)
444
                        geom = geom.cloneGeometry();
445
                    geom.reProject(ct);
446
                }
447
                //System.out.println("Rect?ngulo de selecci?n = "+ rect);
448
                //System.out.println("Rect?ngulo de la geometr?a = "+ geom.getBounds2D());
449
                if (geom.intersects(rect)){
450
                    bitset.set(index, true);
451
                }
452

    
453
            }
454
            va.stop();
455
        } catch (DriverIOException e) {
456
            // TODO Auto-generated catch block
457
            e.printStackTrace();
458
        }
459
        return bitset;
460

    
461
    }
462

    
463
    /* (non-Javadoc)
464
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByPoint(java.awt.geom.Point2D, double)
465
     */
466
    public FBitSet queryByPoint(Point2D p, double tolerance)
467
    throws DriverException {
468
        // TODO: OJO!!!!. Est? implementado como un rectangulo.
469
        // Lo correcto deber?a ser calculando las distancias reales
470
        // es decir, con un c?rculo.
471
        Rectangle2D recPoint = new Rectangle2D.Double(p.getX() - (tolerance / 2),
472
                p.getY() - (tolerance / 2), tolerance, tolerance);
473
        return queryByRect(recPoint);
474
    }
475
    private IGeometry getGeometry(Rectangle2D r){
476
            GeneralPathX resul = new GeneralPathX();
477
                Point2D[] vs=new Point2D[5];
478
                vs[0]=new Point2D.Double(r.getX(),r.getY());
479
            vs[1]=new Point2D.Double(r.getMaxX(),r.getY());
480
            vs[2]=new Point2D.Double(r.getMaxX(),r.getMaxY());
481
            vs[3]=new Point2D.Double(r.getX(),r.getMaxY());
482
            vs[4]=new Point2D.Double(r.getX(),r.getY());
483
                for (int i = 0; i < vs.length; i++) {
484
                        if (i == 0) {
485
                                resul.moveTo(vs[i].getX(),vs[i].getY());
486
                        } else {
487
                                resul.lineTo(vs[i].getX(),vs[i].getY());
488
                        }
489
                }
490
                return ShapeFactory.createPolygon2D(resul);
491
    }
492
}