Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / operations / strategies / AnnotationStrategy.java @ 4795

History | View | Annotate | Download (17.6 KB)

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

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

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

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

    
49

    
50
/**
51
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
52
 * anotaciones.
53
 *
54
 * @author Vicente Caballero Navarro
55
 */
56
public class AnnotationStrategy extends DefaultStrategy {
57
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
58
        private FSymbol symbolPoint=new FSymbol(FShape.POINT,Color.black);
59
        //private FLyrAnnotation la;
60
        //private ArrayList m_labels;
61

    
62

    
63
        /**
64
     * Crea un nuevo AnotationStrategy.
65
     *
66
     * @param layer DOCUMENT ME!
67
     */
68
    public AnnotationStrategy(FLayer layer) {
69
        super(layer);
70
        capa = (FLyrAnnotation) layer;
71
        symbolPoint.setSize(5);
72
    }
73
    /**
74
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
75
         *                 java.awt.Graphics2D, FStyle2D)
76
         */
77
        public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
78
                Cancellable cancel) throws DriverException {
79
                int numReg;
80
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
81
                VectorialLegend l=(VectorialLegend)lyrAnnotation.getLegend();
82
                FBitSet bitSet=lyrAnnotation.getRecordset().getSelection();
83
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
84
                boolean inPixels=lyrAnnotation.isInPixels();
85
                FSymbol theSymbol = l.getDefaultSymbol();
86
                theSymbol.setFontSizeInPixels(inPixels);
87
                System.out.println("Dibujando Anotaciones...");
88
                ViewPort vp=viewPort;//capa.getFMap().getViewPort();
89
                AffineTransform at=vp.getAffineTransform();
90
                try {
91

    
92
                int numRows=lyrAnnotation.getSource().getShapeCount();
93
                //long numRows=lyrAnnotation.getRecordset().getRowCount();
94
                FontMetrics metrics = g.getFontMetrics();
95
                        for (numReg = 0; numReg < numRows; numReg++) {
96
                                if (cancel.isCanceled()) {
97
                                        break;
98
                                }
99
                                if (((FLyrAnnotation) capa).getDelBitSet().get(numReg))continue;
100
                                FLabel theLabel = (FLabel) ((FLyrAnnotation) capa).getLabel(numReg);
101
                                if ((theLabel == null) || (theLabel.getOrig() == null))
102
                                        continue;
103

    
104
                                Rectangle2D r=getBoundBox(theLabel.getOrig(), g,(float)theLabel.getHeight(), theLabel.getJustification(),vp,theLabel.getString());
105
                                theLabel.setBoundBox(r);
106
                                if (elExtent.intersects(r)) {
107
                                        FGraphicUtilities.DrawShape(g,at,new FPoint2D(vp.fromMapPoint(theLabel.getOrig())),symbolPoint);
108
                                        if (bitSet.get(numReg)) {
109
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,true);
110
                                        }else{
111
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,false);
112
                                        }
113
                                }
114
                        }
115
                } catch (DriverIOException e) {
116
                        e.printStackTrace();
117
                }
118
        }
119
         /**
120
     * Construcci?n del rect?ngulo
121
     *
122
     * @param p
123
     * @param g DOCUMENT ME!
124
     * @param justification DOCUMENT ME!
125
     * @param vp DOCUMENT ME!
126
     *
127
     * @return
128
     */
129
    public Rectangle2D getBoundBox(Point2D p, Graphics2D g,float hp,
130
        int justification, ViewPort vp,String s) {
131
        Rectangle2D bounding=null;
132
        if (((FLyrAnnotation)capa).isInPixels()){
133
                g.setFont(g.getFont().deriveFont(hp));
134
        }else{
135
                float alturaPixels = (float) ((hp * vp.getAffineTransform().getScaleX())*FLabel.SQUARE);
136
                g.setFont(g.getFont().deriveFont(alturaPixels));
137
        }
138
        FontMetrics metrics = g.getFontMetrics();
139
        int w = metrics.stringWidth(s);
140
        double width = vp.toMapDistance(w);
141
        int h = metrics.getMaxAscent();
142
        double height = vp.toMapDistance(h);
143
        double dist = vp.toMapDistance(3);
144

    
145
        switch (justification) {
146
            case FLabel.LEFT_BOTTOM:
147
                bounding=justification(p, width,height, 0, -dist);
148

    
149
                break;
150

    
151
            case FLabel.LEFT_CENTER:
152
                     bounding=justification(p, width,height, 0, -(height / 2));
153

    
154
                break;
155

    
156
            case FLabel.LEFT_TOP:
157
                     bounding=justification(p,width,height, 0, -height);
158

    
159
                break;
160

    
161
            case FLabel.CENTER_BOTTOM:
162
                     bounding=justification(p, width,height, -(width / 2), -dist);
163

    
164
                break;
165

    
166
            case FLabel.CENTER_CENTER:
167
                     bounding=justification(p, width,height, -(width / 2), -(height / 2));
168

    
169
                break;
170

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

    
174
                break;
175

    
176
            case FLabel.RIGHT_BOTTOM:
177
                     bounding=justification(p, width,height, -width, -dist);
178

    
179
                break;
180

    
181
            case FLabel.RIGHT_CENTER:
182
                     bounding=justification(p, width,height, -width, -(height / 2));
183

    
184
                break;
185

    
186
            case FLabel.RIGHT_TOP:
187
                     bounding=justification(p, width,height, -width, -height);
188

    
189
                break;
190
        }
191

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

    
233
            Rectangle2D extent = viewPort.getAdjustedExtent();
234
            //AffineTransform at = viewPort.getAffineTransform();
235

    
236
            int sc;
237

    
238
            Rectangle2D bounds;
239

    
240
            sc = adapter.getShapeCount();
241

    
242
            long t1 = System.currentTimeMillis();
243
            // logger.debug("getCapa().getRecordset().start()");
244
            ((AlphanumericData) getCapa()).getRecordset().start();
245

    
246
            // TODO: A revisar si es o no conveniente este sistema
247
            // de comunicaci?n con los drivers.
248
            DriverAttributes attr = adapter.getDriverAttributes();
249
            boolean bMustClone = false;
250
            if (attr != null)
251
            {
252
                if (attr.isLoadedInMemory())
253
                {
254
                    bMustClone = attr.isLoadedInMemory();
255
                }
256
            }
257

    
258

    
259
            for (int i = 0; i < sc; i++) {
260

    
261
                bounds = shapeBounds.getShapeBounds(i);
262

    
263
                if (ct != null) {
264
                    bounds = ct.convert(bounds);
265
                }
266

    
267
                if (XRectangle2D.intersectInclusive(extent, bounds)) {
268
                    FSymbol symbol = l.getSymbol(i);
269

    
270
                    if (bitSet.get(i)) {
271
                        symbol = FSymbol.getSymbolForSelection(symbol);
272
                    }
273

    
274
                    geom = driver.getShape(i);
275

    
276
                    // PRUEBA DE VELOCIDAD
277
                    // geom = ShapeFactory.createPolygon2D(new GeneralPathX(bounds));
278

    
279
                    if (ct != null) {
280
                        if (bMustClone)
281
                            geom = geom.cloneGeometry();
282
                        geom.reProject(ct);
283
                    }
284
                    geom.draw(g, viewPort, symbol);
285
                }
286
            }
287

    
288
            // logger.debug("getCapa().getRecordset().stop()");
289
            ((AlphanumericData) getCapa()).getRecordset().stop();
290

    
291
            long t2 = System.currentTimeMillis();
292
            // logger.debug("adapter.stop()");
293
            adapter.stop();
294

    
295
            // System.out.println(t2 - t1);
296
        } catch (DriverIOException e) {
297
            throw new DriverException(e);
298
        } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
299
            throw new DriverException(e);
300
        } catch (DriverException e) {
301
            throw new DriverException(e);
302
        } catch (IOException e) {
303
            throw new DriverException(e);
304
        }
305

    
306
        }
307

    
308
    /* (non-Javadoc)
309
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.core.IGeometry, int)
310
     */
311
    public FBitSet queryByShape(IGeometry g, int relationship)
312
    throws DriverException, VisitException {
313
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
314
        FLyrVect lyr = (FLyrVect) capa;
315
        if (lyr.getSpatialIndex() == null)
316
            return super.queryByShape(g, relationship);
317

    
318
        long t1 = System.currentTimeMillis();
319
        ReadableVectorial va = lyr.getSource();
320
        ICoordTrans ct = lyr.getCoordTrans();
321
        Rectangle2D bounds = g.getBounds2D();
322
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
323
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
324
        Envelope env = new Envelope(c1, c2);
325

    
326
        List lstRecs = lyr.getSpatialIndex().query(env);
327
        Integer idRec;
328
        FBitSet bitset = new FBitSet();
329
        Geometry jtsShape = g.toJTSGeometry();
330
        IntersectionMatrix m;
331
        int index;
332
        try {
333
            va.start();
334

    
335
            for (int i=0; i < lstRecs.size(); i++)
336
            {
337
                idRec = (Integer) lstRecs.get(i);
338
                index = idRec.intValue();
339
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
340
                if (ct != null) {
341
                    geom.reProject(ct);
342
                }
343
                Geometry jtsGeom = geom.toJTSGeometry();
344
                switch (relationship) {
345
                case CONTAINS:
346
                    m = jtsShape.relate(jtsGeom);
347
                    if (m.isContains()) {
348
                        bitset.set(index, true);
349
                    }
350
                    break;
351

    
352
                case CROSSES:
353
                    m = jtsShape.relate(jtsGeom);
354
                    if (m.isCrosses(jtsGeom.getDimension(), jtsShape.getDimension())) {
355
                        bitset.set(index, true);
356
                    }
357
                    break;
358

    
359
                case DISJOINT:
360
                    // TODO: CREO QUE EL DISJOINT NO SE PUEDE METER AQUI
361
                    m = jtsShape.relate(jtsGeom);
362
                    if (m.isDisjoint()) {
363
                        bitset.set(index, true);
364
                    }
365
                    break;
366

    
367
                case EQUALS:
368
                    m = jtsShape.relate(jtsGeom);
369
                    if (m.isEquals(jtsGeom.getDimension(), jtsShape.getDimension())) {
370
                        bitset.set(index, true);
371
                    }
372
                    break;
373

    
374
                case INTERSECTS:
375
                    m = jtsShape.relate(jtsGeom);
376
                    if (m.isIntersects()) {
377
                        bitset.set(index, true);
378
                    }
379
                    break;
380

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

    
388
                    break;
389

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

    
397
                    break;
398

    
399
                case WITHIN:
400
                    m = jtsShape.relate(jtsGeom);
401
                    if (m.isWithin()) {
402
                        bitset.set(index, true);
403
                    }
404

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

    
423
        ReadableVectorial va = lyr.getSource();
424
        ICoordTrans ct = lyr.getCoordTrans();
425
        Rectangle2D bounds = rect;
426
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
427
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
428
        Envelope env = new Envelope(c1, c2);
429

    
430
        List lstRecs = lyr.getSpatialIndex().query(env);
431
        Integer idRec;
432
        FBitSet bitset = new FBitSet();
433
        int index;
434
        try {
435
            va.start();
436
            DriverAttributes attr = va.getDriverAttributes();
437
            boolean bMustClone = false;
438
            if (attr != null)
439
            {
440
                if (attr.isLoadedInMemory())
441
                {
442
                    bMustClone = attr.isLoadedInMemory();
443
                }
444
            }
445

    
446
            for (int i=0; i < lstRecs.size(); i++)
447
            {
448
                idRec = (Integer) lstRecs.get(i);
449
                index = idRec.intValue();
450
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
451
                if (ct != null) {
452
                    if (bMustClone)
453
                        geom = geom.cloneGeometry();
454
                    geom.reProject(ct);
455
                }
456
                //System.out.println("Rect?ngulo de selecci?n = "+ rect);
457
                //System.out.println("Rect?ngulo de la geometr?a = "+ geom.getBounds2D());
458
                if (geom.intersects(rect)){
459
                    bitset.set(index, true);
460
                }
461

    
462
            }
463
            va.stop();
464
        } catch (DriverIOException e) {
465
            // TODO Auto-generated catch block
466
            e.printStackTrace();
467
        }
468
        return bitset;
469

    
470
    }
471

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