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 @ 42289

History | View | Annotate | Download (39.9 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.Set;
31
import java.util.TreeSet;
32

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

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

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

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

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

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

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

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

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

    
139
    }
140

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

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

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

    
176
        featureStore = (FeatureStore) dataStore;
177

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

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

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

    
189
        this.setLegend(legend);
190

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

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

    
202
        this.delegate(dataStore);
203

    
204
        dataStore.addObserver(this);
205

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

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

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

    
236
    }
237

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

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

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

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

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

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

    
287
        try {
288

    
289
            long tini = System.currentTimeMillis();
290

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

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

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

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

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

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

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

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

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

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

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

    
421
        FeatureStore featureStore = null;
422

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

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

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

    
435
            featureStore = getFeatureStore();
436

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

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

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

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

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

    
460
    }
461

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

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

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

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

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

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

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

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

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

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

    
514
    }
515

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

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

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

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

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

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

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

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

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

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

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

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

    
605
    }
606

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

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

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

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

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

    
644
    }
645

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

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

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

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

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

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

    
681
        return clonedLayer;
682
    }
683

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

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

    
705
            Envelope geomBounds = geom.getEnvelope();
706

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

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

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

    
734
            }
735

    
736
        }
737
        return onePoint;
738
    }
739

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
869
    }
870

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

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

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

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

    
922
    }
923

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

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

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

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

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

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

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

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

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

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

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

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

    
1015
    private boolean isLayerToSnap() {
1016

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

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

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

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

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

    
1076
    public static class RegisterPersistence implements Callable {
1077

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

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

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

    
1102
            return Boolean.TRUE;
1103
        }
1104
    }
1105

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

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

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

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

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

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

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

    
1166
}