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

History | View | Annotate | Download (39.3 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
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.mapcontext.layers.vectorial;
25

    
26
import java.awt.Graphics2D;
27
import java.awt.Point;
28
import java.awt.geom.AffineTransform;
29
import java.awt.geom.Point2D;
30
import java.awt.image.BufferedImage;
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.persistence.exception.PersistenceRuntimeException;
93
import org.gvsig.tools.task.Cancellable;
94

    
95
/**
96
 * Capa b?sica Vectorial.
97
 * 
98
 */
99

    
100
public class FLyrVect extends FLyrDefault implements VectorLayer,
101
    LegendContentsChangedListener, Observer {
102

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

    
108
    /** Leyenda de la capa vectorial */
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.
155
     * Esta operacion no se deneria poder hacer 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
404
     *             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

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

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

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

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

    
481

    
482
            vectorLegend = (IVectorLegend) state.get("legend");
483

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

    
490

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

    
501
            if ( isLabeled.booleanValue() ) {
502
                this.setIsLabeled(true);
503
                this.setLabelingStrategy(labelingStrategy);
504
            } else {
505
                this.setIsLabeled(false);
506
                this.setLabelingStrategy(null);
507
            }
508

    
509
            typeShape = state.getInt("typeShape");
510

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

    
518
    }
519

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

    
533
        return "layer" + ret.substring(ret.indexOf('@') + 1);
534
    }
535

    
536
    public boolean isEditing() {
537
        FeatureStore fs = getFeatureStore();
538
        if (fs == null) {
539
            /*
540
             * This happens when layer is not available, for example,
541
             * it was not possible to load from persistence
542
             */
543
            return false;
544
        } else {
545
            return fs.isEditing();
546
        }
547
    }
548
    
549
    
550
    public void setEditing(boolean b) throws StartEditionLayerException {
551
        
552
        try {
553
            throw new RuntimeException();
554
        } catch (Throwable th) {
555
            logger.info("This method is deprecated. ", th);
556
        }
557
        
558
        if (b == super.isEditing()) {
559
            return;
560
        }
561
        
562
        super.setEditing(b);
563
        FeatureStore fs = getFeatureStore();
564
        if (b) {
565
            try {
566
                fs.edit();
567
            } catch (DataException e) {
568
                throw new StartEditionLayerException(getName(), e);
569
            }
570
        }
571
        setSpatialCacheEnabled(b);
572
        callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
573
    }
574

    
575

    
576
    /**
577
     * @deprecated Use {@link #getSpatialCache()}
578
     */
579
    public void clearSpatialCache() {
580
        spatialCache.clearAll();
581
    }
582

    
583
    /**
584
     * @deprecated Use {@link #getSpatialCache()}
585
     */
586
    public boolean isSpatialCacheEnabled() {
587
        return spatialCache.isEnabled();
588
    }
589

    
590
    /**
591
     * @deprecated Use {@link #getSpatialCache()}
592
     */
593
    public void setSpatialCacheEnabled(boolean spatialCacheEnabled) {
594
        spatialCache.setEnabled(spatialCacheEnabled);
595
    }
596

    
597
    public SpatialCache getSpatialCache() {
598
        return spatialCache;
599
    }
600

    
601
    /**
602
     * Siempre es un numero mayor de 1000
603
     * 
604
     * @param maxFeatures
605
     */
606
    public void setMaxFeaturesInEditionCache(int maxFeatures) {
607
        if (maxFeatures > spatialCache.getMaxFeatures()) {
608
            spatialCache.setMaxFeatures(maxFeatures);
609
        }
610

    
611
    }
612

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

    
626
    public void reload() throws ReloadLayerException {
627
        super.reload();
628
        try {
629
            getFeatureStore().refresh();
630
        } catch (Exception e) {
631
            throw new ReloadLayerException(getName(), e);
632
        }
633
    }
634

    
635
    protected void setLoadSelection(Object xml) {
636
        // this.loadSelection = xml;
637
    }
638

    
639
    protected void setLoadLegend(IVectorLegend legend) {
640
        this.loadLegend = legend;
641
    }
642

    
643
    protected void putLoadSelection() {
644
        // if (this.loadSelection == null) return;
645
        // try {
646
        // this.getRecordset().getSelectionSupport().setXMLEntity(this.loadSelection);
647
        // } catch (ReadDriverException e) {
648
        // throw new XMLException(e);
649
        // }
650
        // this.loadSelection = null;
651

    
652
    }
653

    
654
    protected void putLoadLegend() throws LegendLayerException {
655
        if (this.loadLegend == null) {
656
            return;
657
        }
658
        this.setLegend(this.loadLegend);
659
        this.loadLegend = null;
660
    }
661

    
662
    protected void cleanLoadOptions() {
663
        this.loadLegend = null;
664
    }
665

    
666
    public boolean isWritable() {
667
        return getFeatureStore().allowWrite();
668
    }
669

    
670
    public FLayer cloneLayer() throws Exception {
671
        FLyrVect clonedLayer = new FLyrVect();
672
        clonedLayer.bindToDataStore(getDataStore());
673
        // if (isJoined()) {
674
        // clonedLayer.setIsJoined(true);
675
        // }
676
        clonedLayer.setVisible(isVisible());
677
        // clonedLayer.setISpatialIndex(getISpatialIndex());
678
        clonedLayer.setName(getName());
679
        clonedLayer.setCoordTrans(getCoordTrans());
680

    
681
        clonedLayer.setLegend((IVectorLegend) getLegend().cloneLegend());
682

    
683
        clonedLayer.setIsLabeled(isLabeled());
684
        ILabelingStrategy labelingStrategy = getLabelingStrategy();
685
        if (labelingStrategy != null) {
686
            clonedLayer.setLabelingStrategy(labelingStrategy);
687
        }
688

    
689
        return clonedLayer;
690
    }
691

    
692
    protected boolean isOnePoint(AffineTransform graphicsTransform,
693
        ViewPort viewPort,
694
        double dpi,
695
        CartographicSupport csSym,
696
        Geometry geom,
697
        int[] xyCoords) {
698
        return isOnePoint(graphicsTransform, viewPort, geom, xyCoords)
699
            && csSym.getCartographicSize(viewPort, dpi, geom) <= 1;
700
    }
701

    
702
    private boolean isOnePoint(AffineTransform graphicsTransform,
703
        ViewPort viewPort,
704
        Geometry geom,
705
        int[] xyCoords) {
706
        boolean onePoint = false;
707
        int type = geom.getType();
708
        if (type == Geometry.TYPES.NULL) {
709
            return false;
710
        }
711
        if (type != Geometry.TYPES.POINT && type != Geometry.TYPES.MULTIPOINT) {
712

    
713
            Envelope geomBounds = geom.getEnvelope();
714

    
715
            // ICoordTrans ct = getCoordTrans();
716

    
717
            // Se supone que la geometria ya esta reproyectada
718
            // if (ct!=null) {
719
            // // geomBounds = ct.getInverted().convert(geomBounds);
720
            // geomBounds = geomBounds.convert(ct);
721
            // }
722

    
723
            double dist1Pixel = viewPort.getDist1pixel();
724

    
725
            onePoint =
726
                (geomBounds.getLength(0) <= dist1Pixel && geomBounds.getLength(1) <= dist1Pixel);
727

    
728
            if (onePoint) {
729
                // avoid out of range exceptions
730
                org.gvsig.fmap.geom.primitive.Point p;
731
                try {
732
                    p =
733
                        geomManager.createPoint(geomBounds.getMinimum(0),
734
                            geomBounds.getMinimum(1),
735
                            SUBTYPES.GEOM2D);
736
                    p.transform(viewPort.getAffineTransform());
737
                    p.transform(graphicsTransform);
738
                    xyCoords[0] = (int) p.getX();
739
                    xyCoords[1] = (int) p.getY();
740
                } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
741
                    logger.error("Error creating a point", e);
742
                }
743

    
744
            }
745

    
746
        }
747
        return onePoint;
748
    }
749

    
750
    public boolean isLabeled() {
751
        return isLabeled;
752
    }
753

    
754
    public void setIsLabeled(boolean isLabeled) {
755
        this.isLabeled = isLabeled;
756
    }
757

    
758
    public ILabelingStrategy getLabelingStrategy() {
759
        return strategy;
760
    }
761

    
762
    public void setLabelingStrategy(ILabelingStrategy strategy) {
763
        this.strategy = strategy;
764
        if (strategy == null) {
765
            return;
766
        }
767
        strategy.setLayer(this);
768
        updateDrawVersion();
769
    }
770

    
771
    public void drawLabels(BufferedImage image,
772
        Graphics2D g,
773
        ViewPort viewPort,
774
        Cancellable cancel,
775
        double scale,
776
        double dpi) throws ReadException {
777
        if (strategy != null && isWithinScale(scale)) {
778
            strategy.draw(image, g, scale, viewPort, cancel, dpi);
779
        }
780
    }
781

    
782
    public void printLabels(Graphics2D g,
783
        ViewPort viewPort,
784
        Cancellable cancel,
785
        double scale,
786
        PrintAttributes properties) throws ReadException {
787
        if (strategy != null) {
788
            strategy.print(g, scale, viewPort, cancel, properties);
789
        }
790
    }
791

    
792
    /**
793
     * Return true, because a Vectorial Layer supports HyperLink
794
     * 
795
     * @deprecated the hiperlink functionaliti is out the layer now
796
     */
797
    public boolean allowLinks() {
798
        return false;
799
    }
800

    
801
    public void load() throws LoadLayerException {
802
        super.load();
803
    }
804

    
805
    public FeatureStore getFeatureStore() {
806
        return (FeatureStore) getDataStore();
807
    }
808

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

    
833
    public FeatureSet queryByPoint(org.gvsig.fmap.geom.primitive.Point point,
834
        double tol,
835
        FeatureType featureType) throws DataException {
836
        GeometryManager manager = GeometryLocator.getGeometryManager();
837
        try {
838
            Circle circle =
839
                (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
840
            circle.setPoints(point, tol);
841
            return queryByGeometry(circle, featureType);
842
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
843
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
844
        }
845
    }
846

    
847
    /**
848
     * Input geom must be in the CRS of the view.
849
     * 
850
     * @param geom
851
     * @param featureType
852
     * @return
853
     * @throws DataException
854
     */
855
    public FeatureSet queryByGeometry(Geometry geom, FeatureType featureType) throws DataException {
856
        FeatureQuery featureQuery = featureStore.createFeatureQuery();
857
        String geomName =
858
            featureStore.getDefaultFeatureType()
859
                .getDefaultGeometryAttributeName();
860
        featureQuery.setFeatureType(featureType);
861
        
862
        Geometry query_geo = fromViewPortCRSToSourceCRS(this, geom, true);
863
        IProjection query_proj = getMapContext().getProjection();
864
        if (this.getCoordTrans() != null) {
865
            query_proj = this.getCoordTrans().getPOrig(); 
866
        }
867

    
868
        IntersectsGeometryEvaluator iee =
869
            new IntersectsGeometryEvaluator(
870
                query_geo,
871
                query_proj,
872
                featureStore.getDefaultFeatureType(),
873
                geomName);
874
        featureQuery.setFilter(iee);
875
        featureQuery.setAttributeNames(null);
876
        return getFeatureStore().getFeatureSet(featureQuery);
877

    
878
    }
879

    
880
    /**
881
     * It return the {@link FeatureSet} that intersects with the envelope.
882
     * @param envelope
883
     *          envelope that defines the area for the query.
884
     * @param featureType
885
     *          only the features with this feature type are used in
886
     *          the query.    
887
     * @return
888
     *          the set of features that intersect with the envelope.
889
     * @throws DataException
890
     */
891
    public FeatureSet queryByEnvelope(Envelope envelope, FeatureType featureType) throws DataException {
892
        return queryByEnvelope(envelope, featureType, null);
893
    }
894

    
895
    /**
896
     * It return the {@link FeatureSet} that intersects with the envelope.
897
     * @param envelope
898
     *          envelope that defines the area for the query in viewport CRS
899
     * @param featureType
900
     *          only the features with this feature type are used in
901
     *          the query.
902
     * @param names
903
     *          the feature attributes that have to be checked.
904
     * @return
905
     *          the set of features that intersect with the envelope.
906
     * @throws DataException
907
     */
908
    public FeatureSet queryByEnvelope(Envelope envelope,
909
        FeatureType featureType,
910
        String[] names) throws DataException {
911
        FeatureQuery featureQuery = featureStore.createFeatureQuery();
912
        if (names == null) {
913
            featureQuery.setFeatureType(featureType);
914
        } else {
915
            featureQuery.setAttributeNames(names);
916
            featureQuery.setFeatureTypeId(featureType.getId());
917
        }
918
        String geomName = featureStore.getDefaultFeatureType()
919
                .getDefaultGeometryAttributeName();
920
        
921
        Envelope query_env = fromViewPortCRSToSourceCRS(this, envelope);
922
        IProjection query_proj = getMapContext().getProjection();
923
        if (this.getCoordTrans() != null) {
924
            query_proj = this.getCoordTrans().getPOrig(); 
925
        }
926
        
927
        IntersectsGeometryEvaluator iee =
928
            new IntersectsGeometryEvaluator(
929
                query_env.getGeometry(), query_proj, 
930
                featureStore.getDefaultFeatureType(),
931
                geomName);
932
        featureQuery.setFilter(iee);
933
        return getFeatureStore().getFeatureSet(featureQuery);
934

    
935
    }
936

    
937
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
938
        DataException {
939

    
940
        return getInfo(p, tolerance, cancel, true);
941
    }
942

    
943
    public DynObjectSet getInfo(Point p,
944
        double tolerance,
945
        Cancellable cancel,
946
        boolean fast) throws LoadLayerException, DataException {
947
        Point2D infop = new Point2D.Double(p.x, p.y);
948
        Point2D pReal = this.getMapContext().getViewPort().toMapPoint(infop);
949
        return queryByPoint(pReal,
950
            tolerance,
951
            getFeatureStore().getDefaultFeatureType()).getDynObjectSet(fast);
952
    }
953

    
954
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
955
        double tolerance) throws LoadLayerException, DataException {
956
        return queryByPoint(p,tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
957
    }
958
    
959
    public void legendCleared(LegendClearEvent event) {
960
        this.updateDrawVersion();
961
        LegendChangedEvent e =
962
            LegendChangedEvent.createLegendChangedEvent(legend, legend);
963
        this.callLegendChanged(e);
964
    }
965

    
966
    public boolean symbolChanged(SymbolLegendEvent e) {
967
        this.updateDrawVersion();
968
        LegendChangedEvent ev =
969
            LegendChangedEvent.createLegendChangedEvent(legend, legend);
970
        this.callLegendChanged(ev);
971
        return true;
972
    }
973

    
974
    public void update(Observable observable, Object notification) {
975
        if (observable.equals(this.featureStore)) {
976
            if (notification instanceof FeatureStoreNotification) {
977
                FeatureStoreNotification event =
978
                    (FeatureStoreNotification) notification;
979
                if (event.getType() == FeatureStoreNotification.AFTER_DELETE
980
                    || event.getType() == FeatureStoreNotification.AFTER_UNDO
981
                    || event.getType() == FeatureStoreNotification.AFTER_REDO
982
                    || event.getType() == FeatureStoreNotification.AFTER_REFRESH
983
                    || event.getType() == FeatureStoreNotification.AFTER_UPDATE
984
                    || event.getType() == FeatureStoreNotification.AFTER_UPDATE_TYPE
985
                    || event.getType() == FeatureStoreNotification.SELECTION_CHANGE
986
                    || event.getType() == FeatureStoreNotification.AFTER_INSERT) {
987
                    this.updateDrawVersion();
988
                    
989
                } else if (event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING) {
990
                    
991
                    setSpatialCacheEnabled(false);
992
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
993
                    this.updateDrawVersion();
994
                    
995
                } else if (event.getType() == FeatureStoreNotification.AFTER_STARTEDITING) {
996
                    
997
                    setSpatialCacheEnabled(true);
998
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
999

    
1000
                } else if (event.getType() == FeatureStoreNotification.TRANSFORM_CHANGE){
1001
                    //If a transform has to be applied, try to reload the layer.
1002
                    try {
1003
                        reload();
1004
                    } catch (ReloadLayerException e) {
1005
                        logger.info("While reloading layer.", e);
1006
                        this.setAvailable(false);
1007
                    }
1008
                } else if (event.getType() == FeatureStoreNotification.RESOURCE_CHANGED) {
1009
                    this.setAvailable(false);
1010
                } else         if (event.getType() == FeatureStoreNotification.AFTER_FINISHEDITING) {
1011
                    this.setAvailable(true);
1012
                    setSpatialCacheEnabled(false);
1013
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1014
                    this.updateDrawVersion();
1015
                }
1016
            }
1017
        }
1018
        else if (notification instanceof FeatureDrawnNotification
1019
            && (isEditing() || isLayerToSnap())) {
1020
            // This code is needed in editing mode
1021
                // for all layers involved in snapping
1022
                // (including the layer being edited)
1023
            Geometry geometry =
1024
                ((FeatureDrawnNotification) notification).getDrawnGeometry();
1025
            spatialCache.insert(geometry.getEnvelope(), geometry);
1026
        }
1027
    }
1028

    
1029
    private boolean isLayerToSnap() {
1030

    
1031
        if (this.getMapContext() == null) {
1032
            /*
1033
             * This happens with the graphics layer because it has no parent
1034
             */
1035
            return false;
1036
        } else {
1037
            return this.getMapContext().getLayersToSnap().contains(this);
1038
        }
1039
            
1040
            /*
1041
            Iterator itersnap = this.getMapContext().getLayersToSnap().iterator();
1042
            Object item = null;
1043
            while (itersnap.hasNext()) {
1044
                    item = itersnap.next();
1045
                    if (item == this) {
1046
                            return true;
1047
                    }
1048
            }
1049
                return false;
1050
                */
1051
        }
1052

    
1053
        /*
1054
     * (non-Javadoc)
1055
     * 
1056
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
1057
     */
1058
    public Set getMetadataChildren() {
1059
        Set ret = new TreeSet();
1060
        ret.add(this.featureStore);
1061
        return ret;
1062
    }
1063

    
1064
    /*
1065
     * (non-Javadoc)
1066
     * 
1067
     * @see org.gvsig.metadata.Metadata#getMetadataID()
1068
     */
1069
    public Object getMetadataID() throws MetadataException {
1070
        return "Layer(" + this.getName() + "):"
1071
            + this.featureStore.getMetadataID();
1072
    }
1073

    
1074
    
1075

    
1076
    public GeometryType getTypeVectorLayer() throws DataException,
1077
        LocatorException,
1078
        GeometryTypeNotSupportedException,
1079
        GeometryTypeNotValidException {
1080
        // FIXME Esto deberia de pedirse a FType!!!!
1081
        FeatureStore fs = this.getFeatureStore();
1082
        FeatureType fType = fs.getDefaultFeatureType();
1083
        FeatureAttributeDescriptor attr =
1084
            fType.getAttributeDescriptor(fType.getDefaultGeometryAttributeIndex());
1085
        GeometryType geomType =
1086
            GeometryLocator.getGeometryManager()
1087
                .getGeometryType(attr.getGeometryType(),
1088
                    attr.getGeometrySubType());
1089
        return geomType;
1090
    }
1091

    
1092
    public static void registerPersistent() {
1093
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1094
        if (manager.getDefinition(FLyrDefault.class) == null) {
1095
            FLyrDefault.registerPersistent();
1096
        }
1097
        DynStruct definition =
1098
            manager.addDefinition(FLyrVect.class,
1099
                "FLyrVect",
1100
                "FLyrVect Persistence definition",
1101
                null,
1102
                null);
1103
        definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1104
            "FLyrDefault");
1105

    
1106
        definition.addDynFieldObject("legend")
1107
            .setClassOfValue(IVectorLegend.class)
1108
            .setMandatory(true);
1109
        definition.addDynFieldObject("featureStore")
1110
            .setClassOfValue(FeatureStore.class)
1111
            .setMandatory(true);
1112
        definition.addDynFieldBoolean("isLabeled").setMandatory(true);
1113
        definition.addDynFieldInt("typeShape").setMandatory(true);
1114
        definition.addDynFieldObject("labelingStrategy")
1115
            .setClassOfValue(ILabelingStrategy.class)
1116
            .setMandatory(false);
1117

    
1118
    }
1119

    
1120
    protected void doDispose() throws BaseException {
1121
        dispose(featureStore);
1122
        spatialCache.clearAll();
1123
    }
1124
    
1125
    /**
1126
     * Returns envelope in layer's data source CRS
1127
     * from envelope provided in viewport CRS
1128
     * 
1129
     * @param lyr
1130
     * @param env
1131
     * @return
1132
     */
1133
    public static Envelope fromViewPortCRSToSourceCRS(FLayer lyr, Envelope env) {
1134

    
1135
        if (lyr == null || env == null) {
1136
            return null;
1137
        }
1138

    
1139
        ICoordTrans ct = lyr.getCoordTrans();
1140
        if (ct == null) {
1141
            return env;
1142
        } else {
1143
            return env.convert(ct.getInverted());
1144
        }
1145
    }
1146

    
1147
    /**
1148
     * Returns geometry in layer's data source CRS
1149
     * from geometry provided in viewport CRS
1150
     * 
1151
     * @param lyr
1152
     * @param geo
1153
     * @param clone
1154
     * @return
1155
     */
1156
    public static Geometry fromViewPortCRSToSourceCRS(
1157
        FLayer lyr,
1158
        Geometry geo,
1159
        boolean clone) {
1160
        
1161
        if (lyr == null || geo == null) {
1162
            return null;
1163
        }
1164
        ICoordTrans ct = lyr.getCoordTrans();
1165
        Geometry resp = geo;
1166
        if (clone) {
1167
            resp = resp.cloneGeometry();
1168
        }
1169
        if (ct != null) {
1170
            resp.reProject(ct.getInverted());
1171
        }
1172
        return resp;
1173
    }
1174

    
1175
    
1176
}