Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.mapcontext / org.gvsig.fmap.mapcontext.api / src / main / java / org / gvsig / fmap / mapcontext / layers / vectorial / FLyrVect.java @ 42293

History | View | Annotate | Download (40 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.mapcontext.layers.vectorial;
24

    
25
import java.awt.Graphics2D;
26
import java.awt.Point;
27
import java.awt.geom.AffineTransform;
28
import java.awt.geom.Point2D;
29
import java.awt.image.BufferedImage;
30
import java.util.Iterator;
31
import java.util.Set;
32
import java.util.TreeSet;
33

    
34
import org.cresques.cts.ICoordTrans;
35
import org.cresques.cts.IProjection;
36
import org.slf4j.LoggerFactory;
37

    
38
import org.gvsig.compat.print.PrintAttributes;
39
import org.gvsig.fmap.dal.DataStore;
40
import org.gvsig.fmap.dal.exception.DataException;
41
import org.gvsig.fmap.dal.exception.ReadException;
42
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
43
import org.gvsig.fmap.dal.feature.FeatureQuery;
44
import org.gvsig.fmap.dal.feature.FeatureSet;
45
import org.gvsig.fmap.dal.feature.FeatureStore;
46
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
47
import org.gvsig.fmap.dal.feature.FeatureType;
48
import org.gvsig.fmap.dal.feature.exception.CreateGeometryException;
49
import org.gvsig.fmap.geom.Geometry;
50
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
51
import org.gvsig.fmap.geom.Geometry.TYPES;
52
import org.gvsig.fmap.geom.GeometryLocator;
53
import org.gvsig.fmap.geom.GeometryManager;
54
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
55
import org.gvsig.fmap.geom.primitive.Circle;
56
import org.gvsig.fmap.geom.primitive.Envelope;
57
import org.gvsig.fmap.geom.type.GeometryType;
58
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
59
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
60
import org.gvsig.fmap.mapcontext.MapContextLocator;
61
import org.gvsig.fmap.mapcontext.MapContextManager;
62
import org.gvsig.fmap.mapcontext.ViewPort;
63
import org.gvsig.fmap.mapcontext.exceptions.LegendLayerException;
64
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
65
import org.gvsig.fmap.mapcontext.exceptions.ReloadLayerException;
66
import org.gvsig.fmap.mapcontext.exceptions.StartEditionLayerException;
67
import org.gvsig.fmap.mapcontext.layers.FLayer;
68
import org.gvsig.fmap.mapcontext.layers.FLyrDefault;
69
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
70
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
71
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
72
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
73
import org.gvsig.fmap.mapcontext.rendering.legend.LegendException;
74
import org.gvsig.fmap.mapcontext.rendering.legend.events.FeatureDrawnNotification;
75
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
76
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent;
77
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendContentsChangedListener;
78
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
79
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingStrategy;
80
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
81
import org.gvsig.metadata.exceptions.MetadataException;
82
import org.gvsig.tools.ToolsLocator;
83
import org.gvsig.tools.dynobject.DynObjectSet;
84
import org.gvsig.tools.dynobject.DynStruct;
85
import org.gvsig.tools.exception.BaseException;
86
import org.gvsig.tools.locator.LocatorException;
87
import org.gvsig.tools.observer.Observable;
88
import org.gvsig.tools.observer.Observer;
89
import org.gvsig.tools.persistence.PersistenceManager;
90
import org.gvsig.tools.persistence.PersistentState;
91
import org.gvsig.tools.persistence.exception.PersistenceException;
92
import org.gvsig.tools.task.Cancellable;
93
import org.gvsig.tools.util.Callable;
94

    
95
/**
96
 * Capa b?sica Vectorial.
97
 *
98
 */
99
public class FLyrVect extends FLyrDefault implements VectorLayer,
100
        LegendContentsChangedListener, Observer {
101

    
102
    final static private org.slf4j.Logger logger
103
            = LoggerFactory.getLogger(FLyrVect.class);
104
    private final GeometryManager geomManager
105
            = GeometryLocator.getGeometryManager();
106

    
107
    /**
108
     * Leyenda de la capa vectorial
109
     */
110
    private IVectorLegend legend;
111
    private int typeShape = -1;
112
    private FeatureStore featureStore = null;
113
    private SpatialCache spatialCache = new SpatialCache();
114

    
115
    /**
116
     * An implementation of gvSIG spatial index
117
     */
118
    // protected ISpatialIndex spatialIndex = null;
119
    private IVectorLegend loadLegend = null;
120

    
121
    private boolean isLabeled;
122
    protected ILabelingStrategy strategy;
123
//        private ReprojectDefaultGeometry reprojectTransform;
124

    
125
    public FLyrVect() {
126
        super();
127
    }
128

    
129
    public String getTocImageIcon() {
130
        if (this.isAvailable()) {
131
            return MapContextLocator.getMapContextManager().getIconLayer(this.getDataStore());
132
        } else {
133
            /*
134
             * data store can be be null,
135
             * for example, a layer not loaded from persistence
136
             */
137
            return "layer-icon-unavailable";
138
        }
139

    
140
    }
141

    
142
    /**
143
     * Devuelve el VectorialAdapater de la capa.
144
     *
145
     * @return VectorialAdapter.
146
     */
147
    public DataStore getDataStore() {
148
        if (!this.isAvailable()) {
149
            return null;
150
        }
151
        return featureStore;
152
    }
153

    
154
    /**
155
     * Asigna el data-store a la capa. Esta operacion no se deneria poder hacer
156
     * desde fuera de la clase.
157
     *
158
     * @param dataStore
159
     * @throws LoadLayerException
160
     * @deprecated use {@link #bindToDataStore(DataStore)}
161
     */
162
    public void setDataStore(DataStore dataStore) throws LoadLayerException {
163
        bindToDataStore(dataStore);
164
    }
165

    
166
    /**
167
     * Enlaza la capa con el DataStore indicado.
168
     *
169
     * @param dataStore
170
     * @throws LoadLayerException
171
     */
172
    protected void bindToDataStore(DataStore dataStore) throws LoadLayerException {
173
        if (this.featureStore != null && this.featureStore != dataStore) {
174
            this.featureStore.deleteObserver(this);
175
        }
176

    
177
        featureStore = (FeatureStore) dataStore;
178

    
179
        MapContextManager mapContextManager
180
                = MapContextLocator.getMapContextManager();
181

    
182
        //Set the legend
183
        IVectorLegend legend
184
                = (IVectorLegend) mapContextManager.getLegend(dataStore);
185

    
186
        if (legend == null) {
187
            throw new LegendLayerException(this.getName());
188
        }
189

    
190
        this.setLegend(legend);
191

    
192
        //Set the labeling strategy
193
        ILabelingStrategy labeler
194
                = (ILabelingStrategy) mapContextManager.getLabelingStrategy(dataStore);
195

    
196
        if (labeler != null) {
197
            labeler.setLayer(this);
198
            this.setLabelingStrategy(labeler);
199
            this.setIsLabeled(true); // TODO: ac? no s'hauria de detectar si t?
200
            // etiquetes?????
201
        }
202

    
203
        this.delegate(dataStore);
204

    
205
        dataStore.addObserver(this);
206

    
207
        ToolsLocator.getDisposableManager().bind(dataStore);
208
    }
209

    
210
    public Envelope getFullEnvelope() throws ReadException {
211
        Envelope rAux;
212
        try {
213
            rAux = getFeatureStore().getEnvelope();
214
        } catch (BaseException e) {
215
            throw new ReadException(getName(), e);
216
        }
217

    
218
        // Esto es para cuando se crea una capa nueva con el fullExtent de ancho
219
        // y alto 0.
220
        if (rAux == null || rAux.isEmpty() || rAux.getMaximum(0) - rAux.getMinimum(0) == 0
221
                && rAux.getMaximum(1) - rAux.getMinimum(1) == 0) {
222
            try {
223
                rAux
224
                        = geomManager.createEnvelope(0, 0, 90, 90, SUBTYPES.GEOM2D);
225
            } catch (CreateEnvelopeException e) {
226
                logger.error("Error creating the envelope", e);
227
                e.printStackTrace();
228
            }
229
        }
230
        // Si existe reproyecci?n, reproyectar el extent
231
        ICoordTrans ct = getCoordTrans();
232
        if (ct != null) {
233
            rAux = rAux.convert(ct);
234
        }
235
        return rAux;
236

    
237
    }
238

    
239
    /**
240
     * Draws using IFeatureIterator. This method will replace the old draw(...)
241
     * one.
242
     *
243
     * @autor jaume dominguez faus - jaume.dominguez@iver.es
244
     * @param image
245
     * @param g
246
     * @param viewPort
247
     * @param cancel
248
     * @param scale
249
     * @throws ReadDriverException
250
     */
251
    public void draw(BufferedImage image,
252
            Graphics2D g,
253
            ViewPort viewPort,
254
            Cancellable cancel,
255
            double scale) throws ReadException {
256

    
257
        if (legend == null) {
258
            return;
259
        }
260

    
261
        if (!this.isWithinScale(scale)) {
262
            return;
263
        }
264
        if (cancel.isCanceled()) {
265
            return;
266
        }
267

    
268
        if (spatialCache.isEnabled()) {
269
            spatialCache.clearAll();
270
            legend.addDrawingObserver(this);
271
        }
272

    
273
        FeatureQuery featureQuery = null;
274
        try {
275
            FeatureAttributeDescriptor featureAttributeDescriptor
276
                    = getFeatureStore().getDefaultFeatureType().getDefaultTimeAttribute();
277

    
278
            if ((viewPort.getTime() != null) && (featureAttributeDescriptor != null)) {
279
                featureQuery = getFeatureStore().createFeatureQuery();
280
                IntersectsTimeEvaluator intersectsTimeEvaluator
281
                        = new IntersectsTimeEvaluator(viewPort.getTime(), featureAttributeDescriptor.getName());
282
                featureQuery.addFilter(intersectsTimeEvaluator);
283
            }
284
        } catch (DataException e1) {
285
            logger.error("Impossible to get the temporal filter", e1);
286
        }
287

    
288
        try {
289

    
290
            long tini = System.currentTimeMillis();
291

    
292
            legend.draw(image,
293
                    g,
294
                    viewPort,
295
                    cancel,
296
                    scale,
297
                    null,
298
                    getCoordTrans(),
299
                    getFeatureStore(),
300
                    featureQuery);
301

    
302
            logger.debug("Layer " + this.getName() + " drawn in "
303
                    + (System.currentTimeMillis() - tini) + " milliseconds.");
304

    
305
        } catch (LegendException e) {
306
            this.setVisible(false);
307
            this.setActive(false);
308
            throw new ReadException(getName(), e);
309
        } finally {
310
            if (spatialCache.isEnabled()) {
311
                legend.deleteDrawingObserver(this);
312
            }
313
        }
314
    }
315

    
316
    public void print(Graphics2D g,
317
            ViewPort viewPort,
318
            Cancellable cancel,
319
            double scale,
320
            PrintAttributes properties) throws ReadException {
321
        if (!this.isWithinScale(scale)) {
322
            return;
323
        }
324
        if (cancel.isCanceled()) {
325
            return;
326
        }
327

    
328
        try {
329
            legend.print(g,
330
                    viewPort,
331
                    cancel,
332
                    scale,
333
                    null,
334
                    getCoordTrans(),
335
                    getFeatureStore(),
336
                    null,
337
                    properties);
338

    
339
        } catch (LegendException e) {
340
            this.setVisible(false);
341
            this.setActive(false);
342
            throw new ReadException(getName(), e);
343
        }
344
    }
345

    
346
    public void setLegend(IVectorLegend legend) throws LegendLayerException {
347
        if (this.legend == legend) {
348
            return;
349
        }
350
        if (this.legend != null && this.legend.equals(legend)) {
351
            return;
352
        }
353
        IVectorLegend oldLegend = this.legend;
354
        this.legend = legend;
355
        if (oldLegend != null) {
356
            oldLegend.removeLegendListener(this);
357
            oldLegend.deleteDrawingObserver(this);
358
        }
359
        if (legend != null) {
360
            this.legend.addDrawingObserver(this);
361
            this.legend.addLegendListener(this);
362
        }
363
        LegendChangedEvent e
364
                = LegendChangedEvent.createLegendChangedEvent(oldLegend, this.legend);
365
        e.setLayer(this);
366
        updateDrawVersion();
367
        callLegendChanged(e);
368
    }
369

    
370
    /**
371
     * Devuelve la Leyenda de la capa.
372
     *
373
     * @return Leyenda.
374
     */
375
    public ILegend getLegend() {
376
        return legend;
377
    }
378

    
379
    public int getShapeType() throws ReadException {
380
        if (typeShape == -1) {
381
            FeatureType featureType = null;
382
            try {
383
                if (getDataStore() != null) {
384
                    featureType
385
                            = (((FeatureStore) getDataStore()).getDefaultFeatureType());
386
                }
387
            } catch (DataException e) {
388
                throw new ReadException(getName(), e);
389
            }
390
            if (featureType != null) {
391
                int indexGeom = featureType.getDefaultGeometryAttributeIndex();
392
                typeShape
393
                        = featureType.getAttributeDescriptor(indexGeom).getGeometryType();
394
            }
395
        }
396
        return typeShape;
397
    }
398

    
399
    /**
400
     * Returns the layer's geometry type
401
     *
402
     * @return the geometry type
403
     *
404
     * @throws ReadException if there is an error getting the geometry type
405
     */
406
    public GeometryType getGeometryType() throws ReadException {
407
        FeatureType featureType = null;
408
        try {
409
            if (getDataStore() != null) {
410
                featureType
411
                        = (((FeatureStore) getDataStore()).getDefaultFeatureType());
412
            }
413
        } catch (DataException e) {
414
            throw new ReadException(getName(), e);
415
        }
416
        return featureType == null ? null : featureType
417
                .getDefaultGeometryAttribute().getGeomType();
418
    }
419

    
420
    public void saveToState(PersistentState state) throws PersistenceException {
421

    
422
        FeatureStore featureStore = null;
423

    
424
        if (!this.isAvailable()) {
425
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
426
            return;
427
        }
428

    
429
        try {
430
            super.saveToState(state);
431

    
432
            if (getLegend() != null) {
433
                state.set("legend", getLegend());
434
            }
435

    
436
            featureStore = getFeatureStore();
437

    
438
            if (featureStore != null) {
439
                state.set("featureStore", featureStore);
440
            }
441

    
442
            state.set("isLabeled", isLabeled);
443

    
444
            if (strategy != null) {
445
                state.set("labelingStrategy", strategy);
446
            }
447

    
448
            if (getLinkProperties() != null) {
449
                state.set("linkProperties", getLinkProperties());
450
            }
451

    
452
            state.set("typeShape", typeShape);
453
        } catch (PersistenceException ex) {
454
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
455
            throw ex;
456
        } catch (RuntimeException ex) {
457
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
458
            throw ex;
459
        }
460

    
461
    }
462

    
463
    public void loadFromState(PersistentState state) throws PersistenceException {
464

    
465
        DataStore store = null;
466
        IVectorLegend vectorLegend = null;
467
        ILabelingStrategy labelingStrategy = null;
468
        Boolean isLabeled = Boolean.FALSE;
469

    
470
        try {
471
            super.loadFromState(state);
472
            store = (DataStore) state.get("featureStore");
473

    
474
            try {
475
                this.bindToDataStore(store);
476
            } catch (LoadLayerException e) {
477
                throw new PersistenceException("Can't bind layer '" + this.getName() + "' to store '" + store.getFullName() + "'.", e);
478
            }
479

    
480
            vectorLegend = (IVectorLegend) state.get("legend");
481

    
482
            try {
483
                this.setLegend(vectorLegend);
484
            } catch (LegendLayerException e) {
485
                throw new PersistenceException("Can't set vector legend to the layer.", e);
486
            }
487

    
488
            try {
489
                isLabeled = (Boolean) state.get("isLabeled");
490
                if (isLabeled.booleanValue()) {
491
                    labelingStrategy = (ILabelingStrategy) state.get("labelingStrategy");
492
                }
493
            } catch (Exception ex) {
494
                throw new PersistenceException("Can't load labeling strategi from persistent state.",
495
                        ex);
496
            }
497

    
498
            if (isLabeled.booleanValue()) {
499
                this.setIsLabeled(true);
500
                this.setLabelingStrategy(labelingStrategy);
501
            } else {
502
                this.setIsLabeled(false);
503
                this.setLabelingStrategy(null);
504
            }
505

    
506
            typeShape = state.getInt("typeShape");
507

    
508
        } catch (Throwable e) {
509
            String storeName = (store == null) ? "unknow" : store.getFullName();
510
            logger.warn("can't load layer '" + this.getName() + "' (store=" + storeName + ") from persisted state.", e);
511
            this.setAvailable(false);
512
            return;
513
        }
514

    
515
    }
516

    
517
    /**
518
     * Sobreimplementaci?n del m?todo toString para que las bases de datos
519
     * identifiquen la capa.
520
     *
521
     * @return DOCUMENT ME!
522
     */
523
    public String toString() {
524
        /*
525
         * Se usa internamente para que la parte de datos identifique de forma
526
         * un?voca las tablas
527
         */
528
        String ret = super.toString();
529

    
530
        return "layer" + ret.substring(ret.indexOf('@') + 1);
531
    }
532

    
533
    public boolean isEditing() {
534
        FeatureStore fs = getFeatureStore();
535
        if (fs == null) {
536
            /*
537
             * This happens when layer is not available, for example,
538
             * it was not possible to load from persistence
539
             */
540
            return false;
541
        } else {
542
            return fs.isEditing();
543
        }
544
    }
545

    
546
    public void setEditing(boolean b) throws StartEditionLayerException {
547

    
548
        try {
549
            throw new RuntimeException();
550
        } catch (Throwable th) {
551
            logger.info("This method is deprecated. ", th);
552
        }
553

    
554
        if (b == super.isEditing()) {
555
            return;
556
        }
557

    
558
        super.setEditing(b);
559
        FeatureStore fs = getFeatureStore();
560
        if (b) {
561
            try {
562
                fs.edit();
563
            } catch (DataException e) {
564
                throw new StartEditionLayerException(getName(), e);
565
            }
566
        }
567
        setSpatialCacheEnabled(b);
568
        callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
569
    }
570

    
571
    /**
572
     * @deprecated Use {@link #getSpatialCache()}
573
     */
574
    public void clearSpatialCache() {
575
        spatialCache.clearAll();
576
    }
577

    
578
    /**
579
     * @deprecated Use {@link #getSpatialCache()}
580
     */
581
    public boolean isSpatialCacheEnabled() {
582
        return spatialCache.isEnabled();
583
    }
584

    
585
    /**
586
     * @deprecated Use {@link #getSpatialCache()}
587
     */
588
    public void setSpatialCacheEnabled(boolean spatialCacheEnabled) {
589
        spatialCache.setEnabled(spatialCacheEnabled);
590
    }
591

    
592
    public SpatialCache getSpatialCache() {
593
        return spatialCache;
594
    }
595

    
596
    /**
597
     * Siempre es un numero mayor de 1000
598
     *
599
     * @param maxFeatures
600
     */
601
    public void setMaxFeaturesInEditionCache(int maxFeatures) {
602
        if (maxFeatures > spatialCache.getMaxFeatures()) {
603
            spatialCache.setMaxFeatures(maxFeatures);
604
        }
605

    
606
    }
607

    
608
    /**
609
     * This method returns a boolean that is used by the FPopMenu to make
610
     * visible the properties menu or not. It is visible by default, and if a
611
     * later don't have to show this menu only has to override this method.
612
     *
613
     * @return If the properties menu is visible (or not)
614
     */
615
    public boolean isPropertiesMenuVisible() {
616
        return true;
617
    }
618

    
619
    public void reload() throws ReloadLayerException {
620
        super.reload();
621
        try {
622
            getFeatureStore().refresh();
623
        } catch (Exception e) {
624
            throw new ReloadLayerException(getName(), e);
625
        }
626
    }
627

    
628
    protected void setLoadSelection(Object xml) {
629
        // this.loadSelection = xml;
630
    }
631

    
632
    protected void setLoadLegend(IVectorLegend legend) {
633
        this.loadLegend = legend;
634
    }
635

    
636
    protected void putLoadSelection() {
637
        // if (this.loadSelection == null) return;
638
        // try {
639
        // this.getRecordset().getSelectionSupport().setXMLEntity(this.loadSelection);
640
        // } catch (ReadDriverException e) {
641
        // throw new XMLException(e);
642
        // }
643
        // this.loadSelection = null;
644

    
645
    }
646

    
647
    protected void putLoadLegend() throws LegendLayerException {
648
        if (this.loadLegend == null) {
649
            return;
650
        }
651
        this.setLegend(this.loadLegend);
652
        this.loadLegend = null;
653
    }
654

    
655
    protected void cleanLoadOptions() {
656
        this.loadLegend = null;
657
    }
658

    
659
    public boolean isWritable() {
660
        return getFeatureStore().allowWrite();
661
    }
662

    
663
    public FLayer cloneLayer() throws Exception {
664
        FLyrVect clonedLayer = new FLyrVect();
665
        clonedLayer.bindToDataStore(getDataStore());
666
        // if (isJoined()) {
667
        // clonedLayer.setIsJoined(true);
668
        // }
669
        clonedLayer.setVisible(isVisible());
670
        // clonedLayer.setISpatialIndex(getISpatialIndex());
671
        clonedLayer.setName(getName());
672
        clonedLayer.setCoordTrans(getCoordTrans());
673

    
674
        clonedLayer.setLegend((IVectorLegend) getLegend().cloneLegend());
675

    
676
        clonedLayer.setIsLabeled(isLabeled());
677
        ILabelingStrategy labelingStrategy = getLabelingStrategy();
678
        if (labelingStrategy != null) {
679
            clonedLayer.setLabelingStrategy(labelingStrategy);
680
        }
681

    
682
        return clonedLayer;
683
    }
684

    
685
    protected boolean isOnePoint(AffineTransform graphicsTransform,
686
            ViewPort viewPort,
687
            double dpi,
688
            CartographicSupport csSym,
689
            Geometry geom,
690
            int[] xyCoords) {
691
        return isOnePoint(graphicsTransform, viewPort, geom, xyCoords)
692
                && csSym.getCartographicSize(viewPort, dpi, geom) <= 1;
693
    }
694

    
695
    private boolean isOnePoint(AffineTransform graphicsTransform,
696
            ViewPort viewPort,
697
            Geometry geom,
698
            int[] xyCoords) {
699
        boolean onePoint = false;
700
        int type = geom.getType();
701
        if (type == Geometry.TYPES.NULL) {
702
            return false;
703
        }
704
        if (type != Geometry.TYPES.POINT && type != Geometry.TYPES.MULTIPOINT) {
705

    
706
            Envelope geomBounds = geom.getEnvelope();
707

    
708
            // ICoordTrans ct = getCoordTrans();
709
            // Se supone que la geometria ya esta reproyectada
710
            // if (ct!=null) {
711
            // // geomBounds = ct.getInverted().convert(geomBounds);
712
            // geomBounds = geomBounds.convert(ct);
713
            // }
714
            double dist1Pixel = viewPort.getDist1pixel();
715

    
716
            onePoint
717
                    = (geomBounds.getLength(0) <= dist1Pixel && geomBounds.getLength(1) <= dist1Pixel);
718

    
719
            if (onePoint) {
720
                // avoid out of range exceptions
721
                org.gvsig.fmap.geom.primitive.Point p;
722
                try {
723
                    p
724
                            = geomManager.createPoint(geomBounds.getMinimum(0),
725
                                    geomBounds.getMinimum(1),
726
                                    SUBTYPES.GEOM2D);
727
                    p.transform(viewPort.getAffineTransform());
728
                    p.transform(graphicsTransform);
729
                    xyCoords[0] = (int) p.getX();
730
                    xyCoords[1] = (int) p.getY();
731
                } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
732
                    logger.error("Error creating a point", e);
733
                }
734

    
735
            }
736

    
737
        }
738
        return onePoint;
739
    }
740

    
741
    public boolean isLabeled() {
742
        return isLabeled;
743
    }
744

    
745
    public void setIsLabeled(boolean isLabeled) {
746
        this.isLabeled = isLabeled;
747
    }
748

    
749
    public ILabelingStrategy getLabelingStrategy() {
750
        return strategy;
751
    }
752

    
753
    public void setLabelingStrategy(ILabelingStrategy strategy) {
754
        this.strategy = strategy;
755
        if (strategy == null) {
756
            return;
757
        }
758
        strategy.setLayer(this);
759
        updateDrawVersion();
760
    }
761

    
762
    public void drawLabels(BufferedImage image,
763
            Graphics2D g,
764
            ViewPort viewPort,
765
            Cancellable cancel,
766
            double scale,
767
            double dpi) throws ReadException {
768
        if (strategy != null && isWithinScale(scale)) {
769
            strategy.draw(image, g, scale, viewPort, cancel, dpi);
770
        }
771
    }
772

    
773
    public void printLabels(Graphics2D g,
774
            ViewPort viewPort,
775
            Cancellable cancel,
776
            double scale,
777
            PrintAttributes properties) throws ReadException {
778
        if (strategy != null) {
779
            strategy.print(g, scale, viewPort, cancel, properties);
780
        }
781
    }
782

    
783
    /**
784
     * Return true, because a Vectorial Layer supports HyperLink
785
     *
786
     * @deprecated the hiperlink functionaliti is out the layer now
787
     */
788
    public boolean allowLinks() {
789
        return false;
790
    }
791

    
792
    public void load() throws LoadLayerException {
793
        super.load();
794
    }
795

    
796
    public FeatureStore getFeatureStore() {
797
        return (FeatureStore) getDataStore();
798
    }
799

    
800
    /**
801
     * @deprecated use instead
802
     * {@link #queryByPoint(org.gvsig.fmap.geom.primitive.Point, double, FeatureType)}
803
     */
804
    public FeatureSet queryByPoint(Point2D mapPoint,
805
            double tol,
806
            FeatureType featureType) throws DataException {
807
        logger.warn("Deprecated use of queryByPoint.");
808
        GeometryManager manager = GeometryLocator.getGeometryManager();
809
        org.gvsig.fmap.geom.primitive.Point center;
810
        try {
811
            center
812
                    = (org.gvsig.fmap.geom.primitive.Point) manager.create(TYPES.POINT,
813
                            SUBTYPES.GEOM2D);
814
            center.setX(mapPoint.getX());
815
            center.setY(mapPoint.getY());
816
            Circle circle
817
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
818
            circle.setPoints(center, tol);
819
            return queryByGeometry(circle, featureType);
820
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
821
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
822
        }
823
    }
824

    
825
    public FeatureSet queryByPoint(org.gvsig.fmap.geom.primitive.Point point,
826
            double tol,
827
            FeatureType featureType) throws DataException {
828
        GeometryManager manager = GeometryLocator.getGeometryManager();
829
        try {
830
            Circle circle
831
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
832
            circle.setPoints(point, tol);
833
            return queryByGeometry(circle, featureType);
834
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
835
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
836
        }
837
    }
838

    
839
    /**
840
     * Input geom must be in the CRS of the view.
841
     *
842
     * @param geom
843
     * @param featureType
844
     * @return
845
     * @throws DataException
846
     */
847
    public FeatureSet queryByGeometry(Geometry geom, FeatureType featureType) throws DataException {
848
        FeatureQuery featureQuery = featureStore.createFeatureQuery();
849
        String geomName
850
                = featureStore.getDefaultFeatureType()
851
                .getDefaultGeometryAttributeName();
852
        featureQuery.setFeatureType(featureType);
853

    
854
        Geometry query_geo = this.transformToSourceCRS(geom, true);
855
        IProjection query_proj = getMapContext().getProjection();
856
        if (this.getCoordTrans() != null) {
857
            query_proj = this.getCoordTrans().getPOrig();
858
        }
859

    
860
        IntersectsGeometryEvaluator iee
861
                = new IntersectsGeometryEvaluator(
862
                        query_geo,
863
                        query_proj,
864
                        featureStore.getDefaultFeatureType(),
865
                        geomName);
866
        featureQuery.setFilter(iee);
867
        featureQuery.setAttributeNames(null);
868
        return getFeatureStore().getFeatureSet(featureQuery);
869

    
870
    }
871

    
872
    /**
873
     * It return the {@link FeatureSet} that intersects with the envelope.
874
     *
875
     * @param envelope envelope that defines the area for the query.
876
     * @param featureType only the features with this feature type are used in
877
     * the query.
878
     * @return the set of features that intersect with the envelope.
879
     * @throws DataException
880
     */
881
    public FeatureSet queryByEnvelope(Envelope envelope, FeatureType featureType) throws DataException {
882
        return queryByEnvelope(envelope, featureType, null);
883
    }
884

    
885
    /**
886
     * It return the {@link FeatureSet} that intersects with the envelope.
887
     *
888
     * @param envelope envelope that defines the area for the query in viewport
889
     * CRS
890
     * @param featureType only the features with this feature type are used in
891
     * the query.
892
     * @param names the feature attributes that have to be checked.
893
     * @return the set of features that intersect with the envelope.
894
     * @throws DataException
895
     */
896
    public FeatureSet queryByEnvelope(Envelope envelope,
897
            FeatureType featureType,
898
            String[] names) throws DataException {
899
        FeatureQuery featureQuery = featureStore.createFeatureQuery();
900
        if (names == null) {
901
            featureQuery.setFeatureType(featureType);
902
        } else {
903
            featureQuery.setAttributeNames(names);
904
            featureQuery.setFeatureTypeId(featureType.getId());
905
        }
906
        String geomName = featureStore.getDefaultFeatureType()
907
                .getDefaultGeometryAttributeName();
908

    
909
        Envelope query_env = fromViewPortCRSToSourceCRS(this, envelope);
910
        IProjection query_proj = getMapContext().getProjection();
911
        if (this.getCoordTrans() != null) {
912
            query_proj = this.getCoordTrans().getPOrig();
913
        }
914

    
915
        IntersectsGeometryEvaluator iee
916
                = new IntersectsGeometryEvaluator(
917
                        query_env.getGeometry(), query_proj,
918
                        featureStore.getDefaultFeatureType(),
919
                        geomName);
920
        featureQuery.setFilter(iee);
921
        return getFeatureStore().getFeatureSet(featureQuery);
922

    
923
    }
924

    
925
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
926
            DataException {
927

    
928
        return getInfo(p, tolerance, cancel, true);
929
    }
930

    
931
    public DynObjectSet getInfo(Point p,
932
            double tolerance,
933
            Cancellable cancel,
934
            boolean fast) throws LoadLayerException, DataException {
935
        Point2D infop = new Point2D.Double(p.x, p.y);
936
        Point2D pReal = this.getMapContext().getViewPort().toMapPoint(infop);
937
        return queryByPoint(pReal,
938
                tolerance,
939
                getFeatureStore().getDefaultFeatureType()).getDynObjectSet(fast);
940
    }
941

    
942
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
943
            double tolerance) throws LoadLayerException, DataException {
944
        return queryByPoint(p, tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
945
    }
946

    
947
    public void legendCleared(LegendClearEvent event) {
948
        this.updateDrawVersion();
949
        LegendChangedEvent e
950
                = LegendChangedEvent.createLegendChangedEvent(legend, legend);
951
        this.callLegendChanged(e);
952
    }
953

    
954
    public boolean symbolChanged(SymbolLegendEvent e) {
955
        this.updateDrawVersion();
956
        LegendChangedEvent ev
957
                = LegendChangedEvent.createLegendChangedEvent(legend, legend);
958
        this.callLegendChanged(ev);
959
        return true;
960
    }
961

    
962
    public void update(Observable observable, Object notification) {
963
        if (observable.equals(this.featureStore)) {
964
            if (notification instanceof FeatureStoreNotification) {
965
                FeatureStoreNotification event
966
                        = (FeatureStoreNotification) notification;
967
                if (event.getType() == FeatureStoreNotification.AFTER_DELETE
968
                        || event.getType() == FeatureStoreNotification.AFTER_UNDO
969
                        || event.getType() == FeatureStoreNotification.AFTER_REDO
970
                        || event.getType() == FeatureStoreNotification.AFTER_REFRESH
971
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE
972
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE_TYPE
973
                        || event.getType() == FeatureStoreNotification.SELECTION_CHANGE
974
                        || event.getType() == FeatureStoreNotification.AFTER_INSERT) {
975
                    this.updateDrawVersion();
976

    
977
                } else if (event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING) {
978

    
979
                    setSpatialCacheEnabled(false);
980
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
981
                    this.updateDrawVersion();
982

    
983
                } else if (event.getType() == FeatureStoreNotification.AFTER_STARTEDITING) {
984

    
985
                    setSpatialCacheEnabled(true);
986
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
987

    
988
                } else if (event.getType() == FeatureStoreNotification.TRANSFORM_CHANGE) {
989
                    //If a transform has to be applied, try to reload the layer.
990
                    try {
991
                        reload();
992
                    } catch (ReloadLayerException e) {
993
                        logger.info("While reloading layer.", e);
994
                        this.setAvailable(false);
995
                    }
996
                } else if (event.getType() == FeatureStoreNotification.RESOURCE_CHANGED) {
997
                    this.setAvailable(false);
998
                } else if (event.getType() == FeatureStoreNotification.AFTER_FINISHEDITING) {
999
                    this.setAvailable(true);
1000
                    setSpatialCacheEnabled(false);
1001
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1002
                    this.updateDrawVersion();
1003
                }
1004
            }
1005
        } else if (notification instanceof FeatureDrawnNotification
1006
                && (isEditing() || isLayerToSnap())) {
1007
            // This code is needed in editing mode
1008
            // for all layers involved in snapping
1009
            // (including the layer being edited)
1010
            Geometry geometry
1011
                    = ((FeatureDrawnNotification) notification).getDrawnGeometry();
1012
            spatialCache.insert(geometry.getEnvelope(), geometry);
1013
        }
1014
    }
1015

    
1016
    private boolean isLayerToSnap() {
1017

    
1018
        if (this.getMapContext() == null) {
1019
            /*
1020
             * This happens with the graphics layer because it has no parent
1021
             */
1022
            return false;
1023
        } else {
1024
            return this.getMapContext().getLayersToSnap().contains(this);
1025
        }
1026

    
1027
        /*
1028
         Iterator itersnap = this.getMapContext().getLayersToSnap().iterator();
1029
         Object item = null;
1030
         while (itersnap.hasNext()) {
1031
         item = itersnap.next();
1032
         if (item == this) {
1033
         return true;
1034
         }
1035
         }
1036
         return false;
1037
         */
1038
    }
1039

    
1040
    /*
1041
     * (non-Javadoc)
1042
     * 
1043
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
1044
     */
1045
    public Set getMetadataChildren() {
1046
        Set ret = new TreeSet();
1047
        ret.add(this.featureStore);
1048
        return ret;
1049
    }
1050

    
1051
    /*
1052
     * (non-Javadoc)
1053
     * 
1054
     * @see org.gvsig.metadata.Metadata#getMetadataID()
1055
     */
1056
    public Object getMetadataID() throws MetadataException {
1057
        return "Layer(" + this.getName() + "):"
1058
                + this.featureStore.getMetadataID();
1059
    }
1060

    
1061
    public GeometryType getTypeVectorLayer() throws DataException,
1062
            LocatorException,
1063
            GeometryTypeNotSupportedException,
1064
            GeometryTypeNotValidException {
1065
        // FIXME Esto deberia de pedirse a FType!!!!
1066
        FeatureStore fs = this.getFeatureStore();
1067
        FeatureType fType = fs.getDefaultFeatureType();
1068
        FeatureAttributeDescriptor attr
1069
                = fType.getAttributeDescriptor(fType.getDefaultGeometryAttributeIndex());
1070
        GeometryType geomType
1071
                = GeometryLocator.getGeometryManager()
1072
                .getGeometryType(attr.getGeometryType(),
1073
                        attr.getGeometrySubType());
1074
        return geomType;
1075
    }
1076

    
1077
    public static class RegisterPersistence implements Callable {
1078

    
1079
        public Object call() {
1080
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1081

    
1082
            DynStruct definition
1083
                    = manager.addDefinition(FLyrVect.class,
1084
                            "FLyrVect",
1085
                            "FLyrVect Persistence definition",
1086
                            null,
1087
                            null);
1088
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1089
                    "FLyrDefault");
1090

    
1091
            definition.addDynFieldObject("legend")
1092
                    .setClassOfValue(IVectorLegend.class)
1093
                    .setMandatory(true);
1094
            definition.addDynFieldObject("featureStore")
1095
                    .setClassOfValue(FeatureStore.class)
1096
                    .setMandatory(true);
1097
            definition.addDynFieldBoolean("isLabeled").setMandatory(true);
1098
            definition.addDynFieldInt("typeShape").setMandatory(true);
1099
            definition.addDynFieldObject("labelingStrategy")
1100
                    .setClassOfValue(ILabelingStrategy.class)
1101
                    .setMandatory(false);
1102

    
1103
            return Boolean.TRUE;
1104
        }
1105
    }
1106

    
1107
    protected void doDispose() throws BaseException {
1108
        dispose(featureStore);
1109
        spatialCache.clearAll();
1110
    }
1111

    
1112
    /**
1113
     * Returns envelope in layer's data source CRS from envelope provided in
1114
     * viewport CRS
1115
     *
1116
     * @param lyr
1117
     * @param env
1118
     * @return
1119
     */
1120
    public static Envelope fromViewPortCRSToSourceCRS(FLayer lyr, Envelope env) {
1121

    
1122
        if (lyr == null || env == null) {
1123
            return null;
1124
        }
1125

    
1126
        ICoordTrans ct = lyr.getCoordTrans();
1127
        if (ct == null) {
1128
            return env;
1129
        } else {
1130
            return env.convert(ct.getInverted());
1131
        }
1132
    }
1133

    
1134
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1135
        return fromViewPortCRSToSourceCRS(this, geom, clone);
1136
    }
1137

    
1138
    /**
1139
     * Returns geometry in layer's data source CRS from geometry provided in
1140
     * viewport CRS
1141
     *
1142
     * @param lyr
1143
     * @param geo
1144
     * @param clone
1145
     * @return
1146
     * @deprecated use the transformToSourceCRS method of layer.
1147
     */
1148
    public static Geometry fromViewPortCRSToSourceCRS(
1149
            FLayer lyr,
1150
            Geometry geo,
1151
            boolean clone) {
1152

    
1153
        if (lyr == null || geo == null) {
1154
            return null;
1155
        }
1156
        ICoordTrans ct = lyr.getCoordTrans();
1157
        Geometry resp = geo;
1158
        if (clone) {
1159
            resp = resp.cloneGeometry();
1160
        }
1161
        if (ct != null) {
1162
            resp.reProject(ct.getInverted());
1163
        }
1164
        return resp;
1165
    }
1166

    
1167
    public Iterator iterator() {
1168
        return this.getFeatureStore().iterator();
1169
    }
1170
}