Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_914 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / operations / strategies / AnnotationStrategy.java @ 11873

History | View | Annotate | Download (19.4 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.ISymbol;
25
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
26
import com.iver.cit.gvsig.fmap.core.v02.FConstant;
27
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
28
import com.iver.cit.gvsig.fmap.core.v02.FLabel;
29
import com.iver.cit.gvsig.fmap.core.v02.FSymbol;
30
import com.iver.cit.gvsig.fmap.drivers.BoundedShapes;
31
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
32
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
33
import com.iver.cit.gvsig.fmap.drivers.VectorialFileDriver;
34
import com.iver.cit.gvsig.fmap.layers.FBitSet;
35
import com.iver.cit.gvsig.fmap.layers.FLayer;
36
import com.iver.cit.gvsig.fmap.layers.FLyrAnnotation;
37
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
38
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
39
import com.iver.cit.gvsig.fmap.layers.SpatialCache;
40
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
41
import com.iver.cit.gvsig.fmap.layers.layerOperations.ClassifiableVectorial;
42
import com.iver.cit.gvsig.fmap.layers.layerOperations.Selectable;
43
import com.iver.cit.gvsig.fmap.layers.layerOperations.SingleLayer;
44
import com.iver.cit.gvsig.fmap.rendering.VectorialLegend;
45
import com.iver.cit.gvsig.fmap.rendering.styling.FStyle2D;
46
import com.iver.utiles.swing.threads.Cancellable;
47
import com.vividsolutions.jts.geom.Geometry;
48
import com.vividsolutions.jts.geom.IntersectionMatrix;
49

    
50

    
51
/**
52
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
53
 * anotaciones.
54
 *
55
 * @author Vicente Caballero Navarro
56
 */
57
public class AnnotationStrategy extends DefaultStrategy {
58
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
59
        private FSymbol symbolPoint=new FSymbol(FShape.POINT,Color.black);
60
        private Graphics2D graphics=null;
61
        private ViewPort viewPort=null;
62
        private double heightDefault=-1;
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, ISymbol)
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
                List lstIndexes=null;
83

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

    
87
                boolean inPixels=lyrAnnotation.isInPixels();
88
                FSymbol theSymbol = (FSymbol) l.getDefaultSymbol();
89
                theSymbol.setFontSizeInPixels(inPixels);
90
                System.out.println("Dibujando Anotaciones...");
91
                this.viewPort=viewPort;//capa.getFMap().getViewPort();
92
                AffineTransform at=viewPort.getAffineTransform();
93
                try {
94
                        int sc;
95
                        sc=lyrAnnotation.getSource().getShapeCount();
96
            // If area of needed extent is less than fullExtent / 4,
97
            // it will be worthy to use SpatialIndex.
98
            // Otherwhise, we will not use it.
99
                        boolean bUseSpatialIndex = false;
100
            if(lyrAnnotation.getISpatialIndex() != null)
101
            {
102
                    if(isSpatialIndexNecessary(elExtent)){
103
                            lstIndexes = lyrAnnotation.getISpatialIndex().query(elExtent);
104
                    sc = lstIndexes.size();
105
                    System.out.println("LISTA DEL SPATIALINDEX.SIZE = " + sc);
106
                    bUseSpatialIndex = true;
107
                    }//if
108
            }//if
109

    
110
                        FontMetrics metrics = g.getFontMetrics();
111
                        SpatialCache cache = lyrAnnotation.getSpatialCache();
112
                        cache.clearAll();
113
                        int numOriginal;
114
                        for (int numReg = 0; numReg < sc; numReg++) {
115
                                if (cancel.isCanceled()){
116
                                        break;
117
                                }
118
                if (bUseSpatialIndex){
119
                    Integer idRec = (Integer) lstIndexes.get(numReg);
120
                    numOriginal = idRec.intValue();
121
                }else{
122
                    numOriginal = numReg;
123
                }
124
                                /* if (lyrAnnotation.getSource() instanceof EditableAdapter)
125
                                        numOriginal=((EditableAdapter)lyrAnnotation.getSource()).getCalculatedIndex(numOriginal);*/
126

    
127
                                FLabel theLabel = lyrAnnotation.getLabel(numOriginal);
128
                                if ((theLabel == null) || (theLabel.getOrig() == null))
129
                                        continue;
130

    
131

    
132
                                Rectangle2D r=null;
133
                                if (inPixels && lyrAnnotation.getMapping().getColumnHeight()==-1) {
134
                                        r=getDefaultBoundBoxinPixels(metrics,theLabel.getOrig(),theLabel.getString());
135
                                }else {
136
                                        r=getBoundBox(theLabel.getOrig(),(float)theLabel.getHeight(), theLabel.getJustification(),theLabel.getString());
137
                                }
138
                                theLabel.setBoundBox(r);
139

    
140
                                if (XRectangle2D.intersectInclusive(elExtent, r))
141
                                {
142
                                        FPoint2D p=new FPoint2D(viewPort.fromMapPoint(new Point2D.Double(r.getX(),r.getY())));
143
                                        symbolPoint.draw(g, at, p);
144
                                        // FGraphicUtilities.DrawShape(g,at,p,symbolPoint);
145
                                        if (bitSet.get(numOriginal)) {
146
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,true);
147
                                        }else{
148
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,false);
149
                                        }
150

    
151

    
152
                                        if (lyrAnnotation.isSpatialCacheEnabled())
153
                                        {
154
                                                if (cache.getMaxFeatures() >= cache.size())
155
                                                {
156
                                                        //         Ya reproyectado todo
157
                                                        IGeometry geo=ShapeFactory.createPoint2D(r.getX(),r.getY());
158
                                                        Rectangle2D re= new Rectangle2D.Double(r.getX(),r.getY(),1,1);
159
                                                        cache.insert(re, geo);
160
                                                }
161
                                        }
162
                                } // XIntersects
163

    
164

    
165
                        }
166

    
167
                //         System.out.println("..................Fin del dibujado ..............");
168
                } catch (DriverIOException e) {
169
                        e.printStackTrace();
170
                }
171
                heightDefault=-1;
172
        }
173
          /**
174
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
175
         *                 java.awt.Graphics2D, ISymbol)
176
         */
177
        public void print(BufferedImage image, Graphics2D g, ViewPort viewPort,
178
                Cancellable cancel) throws DriverException {
179
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
180
                graphics=g;
181
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
182
                List lstIndexes=null;
183

    
184
                VectorialLegend l=(VectorialLegend)lyrAnnotation.getLegend();
185
                FBitSet bitSet=lyrAnnotation.getRecordset().getSelection();
186

    
187
                boolean inPixels=lyrAnnotation.isInPixels();
188
                FSymbol theSymbol = (FSymbol) l.getDefaultSymbol();
189
                theSymbol.setFontSizeInPixels(inPixels);
190
                this.viewPort=viewPort;//capa.getFMap().getViewPort();
191
                AffineTransform at=viewPort.getAffineTransform();
192
                try {
193
                        int sc;
194
                        sc=lyrAnnotation.getSource().getShapeCount();
195
            // If area of needed extent is less than fullExtent / 4,
196
            // it will be worthy to use SpatialIndex.
197
            // Otherwhise, we will not use it.
198
                        boolean bUseSpatialIndex = false;
199
            if(lyrAnnotation.getISpatialIndex() != null)
200
            {
201
                    if(isSpatialIndexNecessary(elExtent)){
202
                            lstIndexes = lyrAnnotation.getISpatialIndex().query(elExtent);
203
                    sc = lstIndexes.size();
204
                    bUseSpatialIndex = true;
205
                    }//if
206
            }//if
207

    
208
                        FontMetrics metrics = g.getFontMetrics();
209
                        //SpatialCache cache = lyrAnnotation.createSpatialCache();
210
                        int numOriginal;
211
                        for (int numReg = 0; numReg < sc; numReg++) {
212
                                if (cancel.isCanceled()){
213
                                        break;
214
                                }
215
                if (bUseSpatialIndex){
216
                    Integer idRec = (Integer) lstIndexes.get(numReg);
217
                    numOriginal = idRec.intValue();
218
                }else{
219
                    numOriginal = numReg;
220
                }
221
                                /* if (lyrAnnotation.getSource() instanceof EditableAdapter)
222
                                        numOriginal=((EditableAdapter)lyrAnnotation.getSource()).getCalculatedIndex(numOriginal);*/
223

    
224
                                FLabel theLabel = lyrAnnotation.getLabel(numOriginal);
225
                                if ((theLabel == null) || (theLabel.getOrig() == null))
226
                                        continue;
227

    
228

    
229
                                Rectangle2D r=null;
230
                                if (inPixels && lyrAnnotation.getMapping().getColumnHeight()==-1) {
231
                                        r=getDefaultBoundBoxinPixels(metrics,theLabel.getOrig(),theLabel.getString());
232
                                }else {
233
                                        r=getBoundBox(theLabel.getOrig(),(float)theLabel.getHeight(), theLabel.getJustification(),theLabel.getString());
234
                                }
235
                                theLabel.setBoundBox(r);
236

    
237
                                if (XRectangle2D.intersectInclusive(elExtent, r))
238
                                {
239
                                        FPoint2D p=new FPoint2D(viewPort.fromMapPoint(new Point2D.Double(r.getX(),r.getY())));
240
                                        FGraphicUtilities.DrawShape(g,at,p,symbolPoint);
241
                                        if (bitSet.get(numOriginal)) {
242
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,true);
243
                                        }else{
244
                                                FGraphicUtilities.DrawAnnotation(g, at, theSymbol, theLabel,metrics,false);
245
                                        }
246

    
247

    
248
                                } // XIntersects
249

    
250

    
251
                        }
252

    
253
                } catch (DriverIOException e) {
254
                        e.printStackTrace();
255
                }
256
                heightDefault=-1;
257
        }
258

    
259
         public Rectangle2D getDefaultBoundBoxinPixels(FontMetrics metrics,
260
                        Point2D p, String s) {
261
                int w = metrics.stringWidth(s);
262
                double width = viewPort.toMapDistance(w);
263
                if (heightDefault == -1) {
264
                        int h = metrics.getMaxAscent();
265
                        heightDefault = viewPort.toMapDistance(h);
266
                }
267
                return new Rectangle2D.Double(p.getX(), p.getY(), width, heightDefault);
268

    
269
        }
270

    
271
         /**
272
                 * Construcci?n del rect?ngulo
273
                 *
274
                 * @param p
275
                 * @param g
276
                 *            DOCUMENT ME!
277
                 * @param justification
278
                 *            DOCUMENT ME!
279
                 * @param vp
280
                 *            DOCUMENT ME!
281
                 *
282
                 * @return
283
                 */
284
    public Rectangle2D getBoundBox(Point2D p, float hp,
285
        int justification,String s) {
286
        //Rectangle2D bounding=null;
287
        if (((FLyrAnnotation)capa).isInPixels()){
288
                graphics.setFont(graphics.getFont().deriveFont(hp));
289
        }else{
290
                float alturaPixels = (float) ((hp * viewPort.getAffineTransform().getScaleX())*FConstant.FONT_HEIGHT_SCALE_FACTOR);
291
                graphics.setFont(graphics.getFont().deriveFont(alturaPixels));
292
        }
293
        FontMetrics metrics = graphics.getFontMetrics();
294
        int w = metrics.stringWidth(s);
295
        double width = viewPort.toMapDistance(w);
296
        int h = metrics.getMaxAscent();
297
        double height = viewPort.toMapDistance(h);
298
        //double dist = viewPort.toMapDistance(3);
299
        return new Rectangle2D.Double(p.getX(), p.getY(), width, height);
300
       /* switch (justification) {
301
            case FLabel.LEFT_BOTTOM:
302
                bounding=justification(p, width,height, 0, 0);
303

304
                break;
305

306
            case FLabel.LEFT_CENTER:
307
                     bounding=justification(p, width,height, 0, -(height / 2));
308

309
                break;
310

311
            case FLabel.LEFT_TOP:
312
                     bounding=justification(p,width,height, 0, -height);
313

314
                break;
315

316
            case FLabel.CENTER_BOTTOM:
317
                     bounding=justification(p, width,height, -(width / 2), -dist);
318

319
                break;
320

321
            case FLabel.CENTER_CENTER:
322
                     bounding=justification(p, width,height, -(width / 2), -(height / 2));
323

324
                break;
325

326
            case FLabel.CENTER_TOP:
327
                     bounding=justification(p, width,height, -(width / 2), -height);
328

329
                break;
330

331
            case FLabel.RIGHT_BOTTOM:
332
                     bounding=justification(p, width,height, -width, -dist);
333

334
                break;
335

336
            case FLabel.RIGHT_CENTER:
337
                     bounding=justification(p, width,height, -width, -(height / 2));
338

339
                break;
340

341
            case FLabel.RIGHT_TOP:
342
                     bounding=justification(p, width,height, -width, -height);
343

344
                break;
345
        }
346

347
        return bounding;
348
        */
349
    }
350
  /*  private Rectangle2D justification(Point2D p, double w,double h, double x, double y) {
351
        Rectangle2D r=new Rectangle2D.Double(p.getX() + x, p.getY() - y, w, h);
352
        return r;
353
    }
354
    */
355

    
356
    /* (non-Javadoc)
357
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.core.IGeometry, int)
358
     */
359
    public FBitSet queryByShape(IGeometry g, int relationship)
360
    throws DriverException, VisitException {
361
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
362
        FLyrVect lyr = (FLyrVect) capa;
363
//        if (lyr.getSpatialIndex() == null)
364
        if(lyr.getISpatialIndex() == null)
365
            return super.queryByShape(g, relationship);
366

    
367
        long t1 = System.currentTimeMillis();
368
        ReadableVectorial va = lyr.getSource();
369
        ICoordTrans ct = lyr.getCoordTrans();
370
        Rectangle2D bounds = g.getBounds2D();
371
//        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
372
//        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
373
//        Envelope env = new Envelope(c1, c2);
374
//        List lstRecs = lyr.getSpatialIndex().query(env);
375
        List lstRecs = lyr.getISpatialIndex().query(bounds);
376
        Integer idRec;
377
        FBitSet bitset = new FBitSet();
378
        Geometry jtsShape = g.toJTSGeometry();
379
        IntersectionMatrix m;
380
        int index;
381
        try {
382
            va.start();
383

    
384
            for (int i=0; i < lstRecs.size(); i++)
385
            {
386
                idRec = (Integer) lstRecs.get(i);
387
                index = idRec.intValue();
388
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
389
                if (ct != null) {
390
                    geom.reProject(ct);
391
                }
392
                Geometry jtsGeom = geom.toJTSGeometry();
393
                switch (relationship) {
394
                case CONTAINS:
395
                    m = jtsShape.relate(jtsGeom);
396
                    if (m.isContains()) {
397
                        bitset.set(index, true);
398
                    }
399
                    break;
400

    
401
                case CROSSES:
402
                    m = jtsShape.relate(jtsGeom);
403
                    if (m.isCrosses(jtsGeom.getDimension(), jtsShape.getDimension())) {
404
                        bitset.set(index, true);
405
                    }
406
                    break;
407

    
408
                case DISJOINT:
409
                    // TODO: CREO QUE EL DISJOINT NO SE PUEDE METER AQUI
410
                    m = jtsShape.relate(jtsGeom);
411
                    if (m.isDisjoint()) {
412
                        bitset.set(index, true);
413
                    }
414
                    break;
415

    
416
                case EQUALS:
417
                    m = jtsShape.relate(jtsGeom);
418
                    if (m.isEquals(jtsGeom.getDimension(), jtsShape.getDimension())) {
419
                        bitset.set(index, true);
420
                    }
421
                    break;
422

    
423
                case INTERSECTS:
424
                    m = jtsShape.relate(jtsGeom);
425
                    if (m.isIntersects()) {
426
                        bitset.set(index, true);
427
                    }
428
                    break;
429

    
430
                case OVERLAPS:
431
                    m = jtsShape.relate(jtsGeom);
432
                    if (m.isOverlaps(jtsGeom.getDimension(), jtsShape.getDimension()))
433
                    {
434
                        bitset.set(index, true);
435
                    }
436

    
437
                    break;
438

    
439
                case TOUCHES:
440
                    m = jtsShape.relate(jtsGeom);
441
                    if (m.isTouches(jtsGeom.getDimension(), jtsShape.getDimension()))
442
                    {
443
                        bitset.set(index, true);
444
                    }
445

    
446
                    break;
447

    
448
                case WITHIN:
449
                    m = jtsShape.relate(jtsGeom);
450
                    if (m.isWithin()) {
451
                        bitset.set(index, true);
452
                    }
453

    
454
                    break;
455
                }
456
            }
457
            va.stop();
458
        } catch (DriverIOException e) {
459
            // TODO Auto-generated catch block
460
            e.printStackTrace();
461
        }
462
        long t2 = System.currentTimeMillis();
463
        logger.debug("queryByShape optimizado sobre la capa " + lyr.getName() + ". " + (t2-t1) + " mseg.");
464
        return bitset;
465
    }
466
    public FBitSet queryByRect(Rectangle2D rect) throws DriverException {
467
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
468
        FLyrAnnotation lyr = (FLyrAnnotation) capa;
469
//        if (lyr.getSpatialIndex() == null)
470
          if(lyr.getISpatialIndex() == null)
471
            return super.queryByRect(rect);
472

    
473
        ReadableVectorial va = lyr.getSource();
474
        ICoordTrans ct = lyr.getCoordTrans();
475
        Rectangle2D bounds = rect;
476
//        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
477
//        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
478
//        Envelope env = new Envelope(c1, c2);
479
//
480
//        List lstRecs = lyr.getSpatialIndex().query(env);
481
        //azabala
482
        List lstRecs = lyr.getISpatialIndex().query(bounds);
483
        Integer idRec;
484
        FBitSet bitset = new FBitSet();
485
        int index;
486
        try {
487
            va.start();
488
            DriverAttributes attr = va.getDriverAttributes();
489
            boolean bMustClone = false;
490
            if (attr != null)
491
            {
492
                if (attr.isLoadedInMemory())
493
                {
494
                    bMustClone = attr.isLoadedInMemory();
495
                }
496
            }
497

    
498
            for (int i=0; i < lstRecs.size(); i++)
499
            {
500
                idRec = (Integer) lstRecs.get(i);
501
                index = idRec.intValue();
502
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
503
                if (ct != null) {
504
                    if (bMustClone)
505
                        geom = geom.cloneGeometry();
506
                    geom.reProject(ct);
507
                }
508
                //System.out.println("Rect?ngulo de selecci?n = "+ rect);
509
                //System.out.println("Rect?ngulo de la geometr?a = "+ geom.getBounds2D());
510
                if (geom.intersects(rect)){
511
                    bitset.set(index, true);
512
                }
513

    
514
            }
515
            va.stop();
516
        } catch (DriverIOException e) {
517
            // TODO Auto-generated catch block
518
            e.printStackTrace();
519
        }
520
        return bitset;
521

    
522
    }
523

    
524
    /* (non-Javadoc)
525
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByPoint(java.awt.geom.Point2D, double)
526
     */
527
    public FBitSet queryByPoint(Point2D p, double tolerance)
528
    throws DriverException {
529
        // TODO: OJO!!!!. Est? implementado como un rectangulo.
530
        // Lo correcto deber?a ser calculando las distancias reales
531
        // es decir, con un c?rculo.
532
        Rectangle2D recPoint = new Rectangle2D.Double(p.getX() - (tolerance / 2),
533
                p.getY() - (tolerance / 2), tolerance, tolerance);
534
        return queryByRect(recPoint);
535
    }
536
    private IGeometry getGeometry(Rectangle2D r){
537
            GeneralPathX resul = new GeneralPathX();
538
                Point2D[] vs=new Point2D[4];
539
                vs[0]=new Point2D.Double(r.getX(),r.getY());
540
            vs[1]=new Point2D.Double(r.getMaxX(),r.getY());
541
            vs[2]=new Point2D.Double(r.getMaxX(),r.getMaxY());
542
            vs[3]=new Point2D.Double(r.getX(),r.getMaxY());
543
            //vs[4]=new Point2D.Double(r.getX(),r.getY());
544
                for (int i = 0; i < vs.length; i++) {
545
                        if (i == 0) {
546
                                resul.moveTo(vs[i].getX(),vs[i].getY());
547
                        } else {
548
                                resul.lineTo(vs[i].getX(),vs[i].getY());
549
                        }
550
                }
551
                resul.closePath();
552
                return ShapeFactory.createPolygon2D(resul);
553
    }
554
}