Statistics
| Revision:

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

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.FGraphicUtilities;
27
import com.iver.cit.gvsig.fmap.core.v02.FLabel;
28
import com.iver.cit.gvsig.fmap.core.v02.FSymbol;
29
import com.iver.cit.gvsig.fmap.drivers.BoundedShapes;
30
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
31
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
32
import com.iver.cit.gvsig.fmap.drivers.VectorialFileDriver;
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.SpatialCache;
39
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
40
import com.iver.cit.gvsig.fmap.layers.layerOperations.ClassifiableVectorial;
41
import com.iver.cit.gvsig.fmap.layers.layerOperations.Selectable;
42
import com.iver.cit.gvsig.fmap.layers.layerOperations.SingleLayer;
43
import com.iver.cit.gvsig.fmap.rendering.VectorialLegend;
44
import com.iver.cit.gvsig.fmap.rendering.styling.FStyle2D;
45
import com.iver.utiles.swing.threads.Cancellable;
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 Graphics2D graphics=null;
60
        private ViewPort viewPort=null;
61
        private double heightDefault=-1;
62
        /**
63
     * Crea un nuevo AnotationStrategy.
64
     *
65
     * @param layer DOCUMENT ME!
66
     */
67
    public AnnotationStrategy(FLayer layer) {
68
        super(layer);
69
        capa = (FLyrAnnotation) layer;
70
        symbolPoint.setSize(5);
71
    }
72
    /**
73
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
74
         *                 java.awt.Graphics2D, ISymbol)
75
         */
76
        public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
77
                Cancellable cancel) throws DriverException {
78
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
79
                graphics=g;
80
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
81
                List lstIndexes=null;
82

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

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

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

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

    
130

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

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

    
150

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

    
163

    
164
                        }
165

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

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

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

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

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

    
227

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

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

    
246

    
247
                                } // XIntersects
248

    
249

    
250
                        }
251

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

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

    
268
        }
269

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

303
                break;
304

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

308
                break;
309

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

313
                break;
314

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

318
                break;
319

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

323
                break;
324

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

328
                break;
329

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

333
                break;
334

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

338
                break;
339

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

343
                break;
344
        }
345

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

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

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

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

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

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

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

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

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

    
436
                    break;
437

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

    
445
                    break;
446

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

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

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

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

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

    
521
    }
522

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