Statistics
| Revision:

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

History | View | Annotate | Download (19.9 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.util.List;
11

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

    
16
import com.hardcode.gdbms.driver.exceptions.InitializeDriverException;
17
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
18
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
19
import com.iver.cit.gvsig.exceptions.visitors.VisitorException;
20
import com.iver.cit.gvsig.fmap.ViewPort;
21
import com.iver.cit.gvsig.fmap.core.FPoint2D;
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.SymbologyFactory;
26
import com.iver.cit.gvsig.fmap.core.symbols.IMarkerSymbol;
27
import com.iver.cit.gvsig.fmap.core.symbols.ISymbol;
28
import com.iver.cit.gvsig.fmap.core.v02.FGraphicUtilities;
29
import com.iver.cit.gvsig.fmap.core.v02.FLabel;
30
import com.iver.cit.gvsig.fmap.core.v02.FSymbol;
31
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
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.SpatialCache;
38
import com.iver.cit.gvsig.fmap.rendering.IVectorLegend;
39
import com.iver.utiles.swing.threads.Cancellable;
40
import com.vividsolutions.jts.geom.Geometry;
41
import com.vividsolutions.jts.geom.IntersectionMatrix;
42

    
43

    
44
/**
45
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
46
 * anotaciones.
47
 *
48
 * @author Vicente Caballero Navarro
49
 */
50
public class AnnotationStrategy extends DefaultStrategy {
51
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
52
        private IMarkerSymbol markerSymbol;
53
        private Graphics2D graphics=null;
54
        private ViewPort viewPort=null;
55
        private double heightDefault=-1;
56

    
57
        {
58
                markerSymbol = SymbologyFactory.createDefaultMarkerSymbol();
59
                markerSymbol.setColor(Color.BLACK);
60
        }
61

    
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
        markerSymbol.setSize(5);
71
    }
72
    /**
73
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
74
         *                 java.awt.Graphics2D, ISymbol, Cancellable)
75
         */
76
        public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
77
                Cancellable cancel) throws ReadDriverException {
78
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
79
                graphics=g;
80
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
81
                List lstIndexes=null;
82

    
83
                IVectorLegend l=(IVectorLegend)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
                                        markerSymbol.draw(g, at, p, null);
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 (ExpansionFileReadException e) {
168
                        throw new ReadDriverException(getCapa().getName(),e);
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, Cancellable)
175
         */
176
        public void print(BufferedImage image, Graphics2D g, ViewPort viewPort,
177
                Cancellable cancel) throws ReadDriverException {
178
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
179
                graphics=g;
180
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
181
                List lstIndexes=null;
182

    
183
                IVectorLegend l=(IVectorLegend)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
                                        markerSymbol.draw(g, at, p, null);
240
                                        //FGraphicUtilities.DrawShape(g,at,p,markerSymbol);
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 (ExpansionFileReadException e) {
254
                        throw new ReadDriverException(getCapa().getName(),e);
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())*FLabel.SQUARE);
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 ReadDriverException, VisitorException {
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
                        } catch (InitializeDriverException e) {
384
                                throw new ReadDriverException(getCapa().getName(),e);
385
                        }
386

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

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

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

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

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

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

    
440
                    break;
441

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

    
449
                    break;
450

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

    
457
                    break;
458
                }
459
            }
460
            va.stop();
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 ReadDriverException, VisitorException {
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
            } catch (InitializeDriverException e) {
489
                                throw new ReadDriverException(getCapa().getName(),e);
490
                        }
491
            DriverAttributes attr = va.getDriverAttributes();
492
            boolean bMustClone = false;
493
            if (attr != null)
494
            {
495
                if (attr.isLoadedInMemory())
496
                {
497
                    bMustClone = attr.isLoadedInMemory();
498
                }
499
            }
500

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

    
517
            }
518
            va.stop();
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 ReadDriverException, VisitorException {
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
}