Statistics
| Revision:

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

History | View | Annotate | Download (18.5 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.edition.EditableAdapter;
33
import com.iver.cit.gvsig.fmap.layers.FBitSet;
34
import com.iver.cit.gvsig.fmap.layers.FLayer;
35
import com.iver.cit.gvsig.fmap.layers.FLyrAnnotation;
36
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
37
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
38
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
39
import com.iver.cit.gvsig.fmap.layers.layerOperations.ClassifiableVectorial;
40
import com.iver.cit.gvsig.fmap.layers.layerOperations.Selectable;
41
import com.iver.cit.gvsig.fmap.layers.layerOperations.SingleLayer;
42
import com.iver.cit.gvsig.fmap.operations.Cancellable;
43
import com.iver.cit.gvsig.fmap.rendering.VectorialLegend;
44
import com.iver.cit.gvsig.fmap.rendering.styling.FStyle2D;
45
import com.iver.cit.gvsig.fmap.spatialindex.ISpatialIndex;
46
import com.vividsolutions.jts.geom.Coordinate;
47
import com.vividsolutions.jts.geom.Envelope;
48
import com.vividsolutions.jts.geom.Geometry;
49
import com.vividsolutions.jts.geom.IntersectionMatrix;
50

    
51

    
52
/**
53
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
54
 * anotaciones.
55
 *
56
 * @author Vicente Caballero Navarro
57
 */
58
public class AnnotationStrategy extends DefaultStrategy {
59
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
60
        private FSymbol symbolPoint=new FSymbol(FShape.POINT,Color.black);
61
        private Graphics2D graphics=null;
62
        private ViewPort viewPort=null;
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
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
80
                graphics=g;
81
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
82
                ISpatialIndex isi=lyrAnnotation.getISpatialIndex();
83
                List list=null;
84

    
85
                VectorialLegend l=(VectorialLegend)lyrAnnotation.getLegend();
86
                FBitSet bitSet=lyrAnnotation.getRecordset().getSelection();
87

    
88
                boolean inPixels=lyrAnnotation.isInPixels();
89
                FSymbol theSymbol = l.getDefaultSymbol();
90
                theSymbol.setFontSizeInPixels(inPixels);
91
                System.out.println("Dibujando Anotaciones...");
92
                this.viewPort=viewPort;//capa.getFMap().getViewPort();
93
                AffineTransform at=viewPort.getAffineTransform();
94
                try {
95
                        int sc;
96
                        if (isi==null){
97
                                sc=lyrAnnotation.getSource().getShapeCount();
98
                        }else{
99
                                list=isi.query(elExtent);
100
                                sc = list.size();
101
                        }
102
                        FontMetrics metrics = g.getFontMetrics();
103
                        for (int numReg = 0; numReg < sc; numReg++) {
104
                                if (cancel.isCanceled()) {
105
                                        break;
106
                                }
107
                                int numOriginal;
108
                                if (isi!=null){
109
                                        Integer idRec = (Integer) list.get(numReg);
110
                                        numOriginal= idRec.intValue();
111
                                }else{
112
                                        numOriginal=numReg;
113
                                }
114
                                if (lyrAnnotation.getSource() instanceof EditableAdapter)
115
                                        numOriginal=((EditableAdapter)lyrAnnotation.getSource()).getCalculatedIndex(numOriginal);
116

    
117
                                FLabel theLabel = (FLabel) ((FLyrAnnotation) capa).getLabel(numOriginal);
118
                                if ((theLabel == null) || (theLabel.getOrig() == null))
119
                                        continue;
120

    
121
                                Rectangle2D r=getBoundBox(theLabel.getOrig(),(float)theLabel.getHeight(), theLabel.getJustification(),theLabel.getString());
122
                                theLabel.setBoundBox(r);
123
                                FGraphicUtilities.DrawShape(g,at,new FPoint2D(viewPort.fromMapPoint(new Point2D.Double(r.getX(),r.getY()))),symbolPoint);
124
                                if (bitSet.get(numOriginal)) {
125
                                        FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,true);
126
                                }else{
127
                                        FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,false);
128
                                }
129
                        }
130
                } catch (DriverIOException e) {
131
                        e.printStackTrace();
132
                }
133
        }
134
         /**
135
     * Construcci?n del rect?ngulo
136
     *
137
     * @param p
138
     * @param g DOCUMENT ME!
139
     * @param justification DOCUMENT ME!
140
     * @param vp DOCUMENT ME!
141
     *
142
     * @return
143
     */
144
    public Rectangle2D getBoundBox(Point2D p, float hp,
145
        int justification,String s) {
146
        Rectangle2D bounding=null;
147
        if (((FLyrAnnotation)capa).isInPixels()){
148
                graphics.setFont(graphics.getFont().deriveFont(hp));
149
        }else{
150
                float alturaPixels = (float) ((hp * viewPort.getAffineTransform().getScaleX())*FLabel.SQUARE);
151
                graphics.setFont(graphics.getFont().deriveFont(alturaPixels));
152
        }
153
        FontMetrics metrics = graphics.getFontMetrics();
154
        int w = metrics.stringWidth(s);
155
        double width = viewPort.toMapDistance(w);
156
        int h = metrics.getMaxAscent();
157
        double height = viewPort.toMapDistance(h);
158
        //double dist = viewPort.toMapDistance(3);
159
        return new Rectangle2D.Double(p.getX(), p.getY(), width, height);
160
       /* switch (justification) {
161
            case FLabel.LEFT_BOTTOM:
162
                bounding=justification(p, width,height, 0, 0);
163

164
                break;
165

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

169
                break;
170

171
            case FLabel.LEFT_TOP:
172
                     bounding=justification(p,width,height, 0, -height);
173

174
                break;
175

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

179
                break;
180

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

184
                break;
185

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

189
                break;
190

191
            case FLabel.RIGHT_BOTTOM:
192
                     bounding=justification(p, width,height, -width, -dist);
193

194
                break;
195

196
            case FLabel.RIGHT_CENTER:
197
                     bounding=justification(p, width,height, -width, -(height / 2));
198

199
                break;
200

201
            case FLabel.RIGHT_TOP:
202
                     bounding=justification(p, width,height, -width, -height);
203

204
                break;
205
        }
206

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

    
250
            Rectangle2D extent = viewPort.getAdjustedExtent();
251
            //AffineTransform at = viewPort.getAffineTransform();
252

    
253
            int sc;
254

    
255
            Rectangle2D bounds;
256

    
257
            sc = adapter.getShapeCount();
258

    
259
            long t1 = System.currentTimeMillis();
260
            // logger.debug("getCapa().getRecordset().start()");
261
            ((AlphanumericData) getCapa()).getRecordset().start();
262

    
263
            // TODO: A revisar si es o no conveniente este sistema
264
            // de comunicaci?n con los drivers.
265
            DriverAttributes attr = adapter.getDriverAttributes();
266
            boolean bMustClone = false;
267
            if (attr != null)
268
            {
269
                if (attr.isLoadedInMemory())
270
                {
271
                    bMustClone = attr.isLoadedInMemory();
272
                }
273
            }
274

    
275

    
276
            for (int i = 0; i < sc; i++) {
277

    
278
                bounds = shapeBounds.getShapeBounds(i);
279

    
280
                if (ct != null) {
281
                    bounds = ct.convert(bounds);
282
                }
283

    
284
                if (XRectangle2D.intersectInclusive(extent, bounds)) {
285
                    FSymbol symbol = l.getSymbol(i);
286

    
287
                    if (bitSet.get(i)) {
288
                        symbol = FSymbol.getSymbolForSelection(symbol);
289
                    }
290

    
291
                    geom = driver.getShape(i);
292

    
293
                    // PRUEBA DE VELOCIDAD
294
                    // geom = ShapeFactory.createPolygon2D(new GeneralPathX(bounds));
295

    
296
                    if (ct != null) {
297
                        if (bMustClone)
298
                            geom = geom.cloneGeometry();
299
                        geom.reProject(ct);
300
                    }
301
                    geom.draw(g, viewPort, symbol);
302
                }
303
            }
304

    
305
            // logger.debug("getCapa().getRecordset().stop()");
306
            ((AlphanumericData) getCapa()).getRecordset().stop();
307

    
308
            long t2 = System.currentTimeMillis();
309
            // logger.debug("adapter.stop()");
310
            adapter.stop();
311

    
312
            // System.out.println(t2 - t1);
313
        } catch (DriverIOException e) {
314
            throw new DriverException(e);
315
        } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
316
            throw new DriverException(e);
317
        } catch (DriverException e) {
318
            throw new DriverException(e);
319
        } catch (IOException e) {
320
            throw new DriverException(e);
321
        }
322

    
323
        }
324

    
325
    /* (non-Javadoc)
326
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.core.IGeometry, int)
327
     */
328
    public FBitSet queryByShape(IGeometry g, int relationship)
329
    throws DriverException, VisitException {
330
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
331
        FLyrVect lyr = (FLyrVect) capa;
332
//        if (lyr.getSpatialIndex() == null)
333
        if(lyr.getISpatialIndex() == null)
334
            return super.queryByShape(g, relationship);
335

    
336
        long t1 = System.currentTimeMillis();
337
        ReadableVectorial va = lyr.getSource();
338
        ICoordTrans ct = lyr.getCoordTrans();
339
        Rectangle2D bounds = g.getBounds2D();
340
//        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
341
//        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
342
//        Envelope env = new Envelope(c1, c2);
343
//        List lstRecs = lyr.getSpatialIndex().query(env);
344
        List lstRecs = lyr.getISpatialIndex().query(bounds);
345
        Integer idRec;
346
        FBitSet bitset = new FBitSet();
347
        Geometry jtsShape = g.toJTSGeometry();
348
        IntersectionMatrix m;
349
        int index;
350
        try {
351
            va.start();
352

    
353
            for (int i=0; i < lstRecs.size(); i++)
354
            {
355
                idRec = (Integer) lstRecs.get(i);
356
                index = idRec.intValue();
357
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
358
                if (ct != null) {
359
                    geom.reProject(ct);
360
                }
361
                Geometry jtsGeom = geom.toJTSGeometry();
362
                switch (relationship) {
363
                case CONTAINS:
364
                    m = jtsShape.relate(jtsGeom);
365
                    if (m.isContains()) {
366
                        bitset.set(index, true);
367
                    }
368
                    break;
369

    
370
                case CROSSES:
371
                    m = jtsShape.relate(jtsGeom);
372
                    if (m.isCrosses(jtsGeom.getDimension(), jtsShape.getDimension())) {
373
                        bitset.set(index, true);
374
                    }
375
                    break;
376

    
377
                case DISJOINT:
378
                    // TODO: CREO QUE EL DISJOINT NO SE PUEDE METER AQUI
379
                    m = jtsShape.relate(jtsGeom);
380
                    if (m.isDisjoint()) {
381
                        bitset.set(index, true);
382
                    }
383
                    break;
384

    
385
                case EQUALS:
386
                    m = jtsShape.relate(jtsGeom);
387
                    if (m.isEquals(jtsGeom.getDimension(), jtsShape.getDimension())) {
388
                        bitset.set(index, true);
389
                    }
390
                    break;
391

    
392
                case INTERSECTS:
393
                    m = jtsShape.relate(jtsGeom);
394
                    if (m.isIntersects()) {
395
                        bitset.set(index, true);
396
                    }
397
                    break;
398

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

    
406
                    break;
407

    
408
                case TOUCHES:
409
                    m = jtsShape.relate(jtsGeom);
410
                    if (m.isTouches(jtsGeom.getDimension(), jtsShape.getDimension()))
411
                    {
412
                        bitset.set(index, true);
413
                    }
414

    
415
                    break;
416

    
417
                case WITHIN:
418
                    m = jtsShape.relate(jtsGeom);
419
                    if (m.isWithin()) {
420
                        bitset.set(index, true);
421
                    }
422

    
423
                    break;
424
                }
425
            }
426
            va.stop();
427
        } catch (DriverIOException e) {
428
            // TODO Auto-generated catch block
429
            e.printStackTrace();
430
        }
431
        long t2 = System.currentTimeMillis();
432
        logger.debug("queryByShape optimizado sobre la capa " + lyr.getName() + ". " + (t2-t1) + " mseg.");
433
        return bitset;
434
    }
435
    public FBitSet queryByRect(Rectangle2D rect) throws DriverException {
436
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
437
        FLyrAnnotation lyr = (FLyrAnnotation) capa;
438
//        if (lyr.getSpatialIndex() == null)
439
          if(lyr.getISpatialIndex() == null)
440
            return super.queryByRect(rect);
441

    
442
        ReadableVectorial va = lyr.getSource();
443
        ICoordTrans ct = lyr.getCoordTrans();
444
        Rectangle2D bounds = rect;
445
//        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
446
//        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
447
//        Envelope env = new Envelope(c1, c2);
448
//
449
//        List lstRecs = lyr.getSpatialIndex().query(env);
450
        //azabala
451
        List lstRecs = lyr.getISpatialIndex().query(bounds);
452
        Integer idRec;
453
        FBitSet bitset = new FBitSet();
454
        int index;
455
        try {
456
            va.start();
457
            DriverAttributes attr = va.getDriverAttributes();
458
            boolean bMustClone = false;
459
            if (attr != null)
460
            {
461
                if (attr.isLoadedInMemory())
462
                {
463
                    bMustClone = attr.isLoadedInMemory();
464
                }
465
            }
466

    
467
            for (int i=0; i < lstRecs.size(); i++)
468
            {
469
                idRec = (Integer) lstRecs.get(i);
470
                index = idRec.intValue();
471
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
472
                if (ct != null) {
473
                    if (bMustClone)
474
                        geom = geom.cloneGeometry();
475
                    geom.reProject(ct);
476
                }
477
                //System.out.println("Rect?ngulo de selecci?n = "+ rect);
478
                //System.out.println("Rect?ngulo de la geometr?a = "+ geom.getBounds2D());
479
                if (geom.intersects(rect)){
480
                    bitset.set(index, true);
481
                }
482

    
483
            }
484
            va.stop();
485
        } catch (DriverIOException e) {
486
            // TODO Auto-generated catch block
487
            e.printStackTrace();
488
        }
489
        return bitset;
490

    
491
    }
492

    
493
    /* (non-Javadoc)
494
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByPoint(java.awt.geom.Point2D, double)
495
     */
496
    public FBitSet queryByPoint(Point2D p, double tolerance)
497
    throws DriverException {
498
        // TODO: OJO!!!!. Est? implementado como un rectangulo.
499
        // Lo correcto deber?a ser calculando las distancias reales
500
        // es decir, con un c?rculo.
501
        Rectangle2D recPoint = new Rectangle2D.Double(p.getX() - (tolerance / 2),
502
                p.getY() - (tolerance / 2), tolerance, tolerance);
503
        return queryByRect(recPoint);
504
    }
505
    private IGeometry getGeometry(Rectangle2D r){
506
            GeneralPathX resul = new GeneralPathX();
507
                Point2D[] vs=new Point2D[4];
508
                vs[0]=new Point2D.Double(r.getX(),r.getY());
509
            vs[1]=new Point2D.Double(r.getMaxX(),r.getY());
510
            vs[2]=new Point2D.Double(r.getMaxX(),r.getMaxY());
511
            vs[3]=new Point2D.Double(r.getX(),r.getMaxY());
512
            //vs[4]=new Point2D.Double(r.getX(),r.getY());
513
                for (int i = 0; i < vs.length; i++) {
514
                        if (i == 0) {
515
                                resul.moveTo(vs[i].getX(),vs[i].getY());
516
                        } else {
517
                                resul.lineTo(vs[i].getX(),vs[i].getY());
518
                        }
519
                }
520
                resul.closePath();
521
                return ShapeFactory.createPolygon2D(resul);
522
    }
523
}