Statistics
| Revision:

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

History | View | Annotate | Download (17.3 KB)

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

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

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

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

    
46

    
47
/**
48
 * Esta clase se encargar? de dibujar de la forma m?s eficiente los temas de
49
 * anotaciones.
50
 *
51
 * @author Vicente Caballero Navarro
52
 */
53
public class AnnotationStrategy extends DefaultStrategy {
54
        private static Logger logger = Logger.getLogger(AnnotationStrategy.class.getName());
55
        //private FLyrAnnotation la;
56
        //private ArrayList m_labels;
57

    
58

    
59
        /**
60
     * Crea un nuevo AnotationStrategy.
61
     *
62
     * @param layer DOCUMENT ME!
63
     */
64
    public AnnotationStrategy(FLayer layer) {
65
        super(layer);
66
        capa = (FLyrAnnotation) layer;
67
    }
68
    /**
69
         * @see com.iver.cit.gvsig.fmap.operations.LayerOperations#draw(java.awt.image.BufferedImage,
70
         *                 java.awt.Graphics2D, FStyle2D)
71
         */
72
        public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
73
                Cancellable cancel) throws DriverException {
74
                int numReg;
75
                FLyrAnnotation lyrAnnotation=(FLyrAnnotation)capa;
76
                VectorialLegend l=(VectorialLegend)lyrAnnotation.getLegend();
77
                FBitSet bitSet=lyrAnnotation.getRecordset().getSelection();
78
                Rectangle2D elExtent = viewPort.getAdjustedExtent();
79
                boolean inPixels=lyrAnnotation.isInPixels();
80
                FSymbol theSymbol = l.getDefaultSymbol();
81
                theSymbol.setFontSizeInPixels(inPixels);
82
                System.out.println("Dibujando Anotaciones...");
83
                ViewPort vp=viewPort;//capa.getFMap().getViewPort();
84
                AffineTransform at=vp.getAffineTransform();
85
                try {
86
                long numRows=lyrAnnotation.getRecordset().getRowCount();
87
                FontMetrics metrics = g.getFontMetrics();
88
                        for (numReg = 0; numReg < numRows; numReg++) {
89
                                if (cancel.isCanceled()) {
90
                                        break;
91
                                }
92
                                if (((FLyrAnnotation) capa).getDelBitSet().get(numReg))continue;
93
                                FLabel theLabel = (FLabel) ((FLyrAnnotation) capa).getLabel(numReg);
94
                                if ((theLabel == null) || (theLabel.getOrig() == null))
95
                                        continue;
96

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

    
137
        switch (justification) {
138
            case FLabel.LEFT_BOTTOM:
139
                bounding=justification(p, width,height, 0, -dist);
140

    
141
                break;
142

    
143
            case FLabel.LEFT_CENTER:
144
                     bounding=justification(p, width,height, 0, -(height / 2));
145

    
146
                break;
147

    
148
            case FLabel.LEFT_TOP:
149
                     bounding=justification(p,width,height, 0, -height);
150

    
151
                break;
152

    
153
            case FLabel.CENTER_BOTTOM:
154
                     bounding=justification(p, width,height, -(width / 2), -dist);
155

    
156
                break;
157

    
158
            case FLabel.CENTER_CENTER:
159
                     bounding=justification(p, width,height, -(width / 2), -(height / 2));
160

    
161
                break;
162

    
163
            case FLabel.CENTER_TOP:
164
                     bounding=justification(p, width,height, -(width / 2), -height);
165

    
166
                break;
167

    
168
            case FLabel.RIGHT_BOTTOM:
169
                     bounding=justification(p, width,height, -width, -dist);
170

    
171
                break;
172

    
173
            case FLabel.RIGHT_CENTER:
174
                     bounding=justification(p, width,height, -width, -(height / 2));
175

    
176
                break;
177

    
178
            case FLabel.RIGHT_TOP:
179
                     bounding=justification(p, width,height, -width, -height);
180

    
181
                break;
182
        }
183

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

    
225
            Rectangle2D extent = viewPort.getAdjustedExtent();
226
            //AffineTransform at = viewPort.getAffineTransform();
227

    
228
            int sc;
229

    
230
            Rectangle2D bounds;
231

    
232
            sc = adapter.getShapeCount();
233

    
234
            long t1 = System.currentTimeMillis();
235
            // logger.debug("getCapa().getRecordset().start()");
236
            ((AlphanumericData) getCapa()).getRecordset().start();
237

    
238
            // TODO: A revisar si es o no conveniente este sistema
239
            // de comunicaci?n con los drivers.
240
            DriverAttributes attr = adapter.getDriverAttributes();
241
            boolean bMustClone = false;
242
            if (attr != null)
243
            {
244
                if (attr.isLoadedInMemory())
245
                {
246
                    bMustClone = attr.isLoadedInMemory();
247
                }
248
            }
249

    
250

    
251
            for (int i = 0; i < sc; i++) {
252

    
253
                bounds = shapeBounds.getShapeBounds(i);
254

    
255
                if (ct != null) {
256
                    bounds = ct.convert(bounds);
257
                }
258

    
259
                if (XRectangle2D.intersectInclusive(extent, bounds)) {
260
                    FSymbol symbol = l.getSymbol(i);
261

    
262
                    if (bitSet.get(i)) {
263
                        symbol = FSymbol.getSymbolForSelection(symbol);
264
                    }
265

    
266
                    geom = driver.getShape(i);
267

    
268
                    // PRUEBA DE VELOCIDAD
269
                    // geom = ShapeFactory.createPolygon2D(new GeneralPathX(bounds));
270

    
271
                    if (ct != null) {
272
                        if (bMustClone)
273
                            geom = geom.cloneGeometry();
274
                        geom.reProject(ct);
275
                    }
276
                    geom.draw(g, viewPort, symbol);
277
                }
278
            }
279

    
280
            // logger.debug("getCapa().getRecordset().stop()");
281
            ((AlphanumericData) getCapa()).getRecordset().stop();
282

    
283
            long t2 = System.currentTimeMillis();
284
            // logger.debug("adapter.stop()");
285
            adapter.stop();
286

    
287
            // System.out.println(t2 - t1);
288
        } catch (DriverIOException e) {
289
            throw new DriverException(e);
290
        } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
291
            throw new DriverException(e);
292
        } catch (DriverException e) {
293
            throw new DriverException(e);
294
        } catch (IOException e) {
295
            throw new DriverException(e);
296
        }
297

    
298
        }
299

    
300
    /* (non-Javadoc)
301
     * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.core.IGeometry, int)
302
     */
303
    public FBitSet queryByShape(IGeometry g, int relationship)
304
    throws DriverException, VisitException {
305
        // Si hay un ?ndice espacial, lo usamos para hacer el query.
306
        FLyrVect lyr = (FLyrVect) capa;
307
        if (lyr.getSpatialIndex() == null)
308
            return super.queryByShape(g, relationship);
309

    
310
        long t1 = System.currentTimeMillis();
311
        ReadableVectorial va = lyr.getSource();
312
        ICoordTrans ct = lyr.getCoordTrans();
313
        Rectangle2D bounds = g.getBounds2D();
314
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
315
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
316
        Envelope env = new Envelope(c1, c2);
317

    
318
        List lstRecs = lyr.getSpatialIndex().query(env);
319
        Integer idRec;
320
        FBitSet bitset = new FBitSet();
321
        Geometry jtsShape = g.toJTSGeometry();
322
        IntersectionMatrix m;
323
        int index;
324
        try {
325
            va.start();
326

    
327
            for (int i=0; i < lstRecs.size(); i++)
328
            {
329
                idRec = (Integer) lstRecs.get(i);
330
                index = idRec.intValue();
331
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
332
                if (ct != null) {
333
                    geom.reProject(ct);
334
                }
335
                Geometry jtsGeom = geom.toJTSGeometry();
336
                switch (relationship) {
337
                case CONTAINS:
338
                    m = jtsShape.relate(jtsGeom);
339
                    if (m.isContains()) {
340
                        bitset.set(index, true);
341
                    }
342
                    break;
343

    
344
                case CROSSES:
345
                    m = jtsShape.relate(jtsGeom);
346
                    if (m.isCrosses(jtsGeom.getDimension(), jtsShape.getDimension())) {
347
                        bitset.set(index, true);
348
                    }
349
                    break;
350

    
351
                case DISJOINT:
352
                    // TODO: CREO QUE EL DISJOINT NO SE PUEDE METER AQUI
353
                    m = jtsShape.relate(jtsGeom);
354
                    if (m.isDisjoint()) {
355
                        bitset.set(index, true);
356
                    }
357
                    break;
358

    
359
                case EQUALS:
360
                    m = jtsShape.relate(jtsGeom);
361
                    if (m.isEquals(jtsGeom.getDimension(), jtsShape.getDimension())) {
362
                        bitset.set(index, true);
363
                    }
364
                    break;
365

    
366
                case INTERSECTS:
367
                    m = jtsShape.relate(jtsGeom);
368
                    if (m.isIntersects()) {
369
                        bitset.set(index, true);
370
                    }
371
                    break;
372

    
373
                case OVERLAPS:
374
                    m = jtsShape.relate(jtsGeom);
375
                    if (m.isOverlaps(jtsGeom.getDimension(), jtsShape.getDimension()))
376
                    {
377
                        bitset.set(index, true);
378
                    }
379

    
380
                    break;
381

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

    
389
                    break;
390

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

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

    
415
        ReadableVectorial va = lyr.getSource();
416
        ICoordTrans ct = lyr.getCoordTrans();
417
        Rectangle2D bounds = rect;
418
        Coordinate c1 = new Coordinate(bounds.getMinX(), bounds.getMinY());
419
        Coordinate c2 = new Coordinate(bounds.getMaxX(), bounds.getMaxY());
420
        Envelope env = new Envelope(c1, c2);
421

    
422
        List lstRecs = lyr.getSpatialIndex().query(env);
423
        Integer idRec;
424
        FBitSet bitset = new FBitSet();
425
        int index;
426
        try {
427
            va.start();
428
            DriverAttributes attr = va.getDriverAttributes();
429
            boolean bMustClone = false;
430
            if (attr != null)
431
            {
432
                if (attr.isLoadedInMemory())
433
                {
434
                    bMustClone = attr.isLoadedInMemory();
435
                }
436
            }
437

    
438
            for (int i=0; i < lstRecs.size(); i++)
439
            {
440
                idRec = (Integer) lstRecs.get(i);
441
                index = idRec.intValue();
442
                IGeometry geom=getGeometry(((FLyrAnnotation)capa).getLabel(index).getBoundBox());
443
                if (ct != null) {
444
                    if (bMustClone)
445
                        geom = geom.cloneGeometry();
446
                    geom.reProject(ct);
447
                }
448
                //System.out.println("Rect?ngulo de selecci?n = "+ rect);
449
                //System.out.println("Rect?ngulo de la geometr?a = "+ geom.getBounds2D());
450
                if (geom.intersects(rect)){
451
                    bitset.set(index, true);
452
                }
453

    
454
            }
455
            va.stop();
456
        } catch (DriverIOException e) {
457
            // TODO Auto-generated catch block
458
            e.printStackTrace();
459
        }
460
        return bitset;
461

    
462
    }
463

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