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

History | View | Annotate | Download (39.7 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
import org.gvsig.tools.util.Callable;
95

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

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

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

    
109
    /** Leyenda de la capa vectorial */
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.
156
     * Esta operacion no se deneria poder hacer 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
405
     *             if there is an error getting the geometry type
406
     */
407
    public GeometryType getGeometryType() throws ReadException {
408
        FeatureType featureType = null;
409
        try {
410
            if (getDataStore() != null) {
411
                featureType =
412
                    (((FeatureStore) getDataStore()).getDefaultFeatureType());
413
            }
414
        } catch (DataException e) {
415
            throw new ReadException(getName(), e);
416
        }
417
        return featureType == null ? null : featureType
418
            .getDefaultGeometryAttribute().getGeomType();
419
    }
420

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

    
423
        FeatureStore featureStore = null;
424

    
425
        if ( !this.isAvailable() ) {
426
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
427
            return;
428
        }
429
        
430
        try {
431
            super.saveToState(state);
432

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

    
437
            featureStore = getFeatureStore();
438

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

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

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

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

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

    
462
    }
463

    
464

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

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

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

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

    
482

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

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

    
491

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

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

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

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

    
519
    }
520

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

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

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

    
576

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

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

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

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

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

    
612
    }
613

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

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

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

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

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

    
653
    }
654

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

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

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

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

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

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

    
690
        return clonedLayer;
691
    }
692

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

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

    
714
            Envelope geomBounds = geom.getEnvelope();
715

    
716
            // ICoordTrans ct = getCoordTrans();
717

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

    
724
            double dist1Pixel = viewPort.getDist1pixel();
725

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

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

    
745
            }
746

    
747
        }
748
        return onePoint;
749
    }
750

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

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

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

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

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

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

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

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

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

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

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

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

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

    
879
    }
880

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

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

    
936
    }
937

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

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

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

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

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

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

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

    
1030
    private boolean isLayerToSnap() {
1031

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

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

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

    
1075
    
1076

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

    
1093
    public static class RegisterPersistence implements Callable {
1094

    
1095
        public Object call() {
1096
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1097

    
1098
            DynStruct definition
1099
                    = manager.addDefinition(FLyrVect.class,
1100
                            "FLyrVect",
1101
                            "FLyrVect Persistence definition",
1102
                            null,
1103
                            null);
1104
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1105
                    "FLyrDefault");
1106

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

    
1119
            return Boolean.TRUE;
1120
        }
1121
    }
1122

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

    
1138
        if (lyr == null || env == null) {
1139
            return null;
1140
        }
1141

    
1142
        ICoordTrans ct = lyr.getCoordTrans();
1143
        if (ct == null) {
1144
            return env;
1145
        } else {
1146
            return env.convert(ct.getInverted());
1147
        }
1148
    }
1149

    
1150
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1151
        return fromViewPortCRSToSourceCRS(this,geom,clone);
1152
    }
1153
    
1154
    
1155
    /**
1156
     * Returns geometry in layer's data source CRS
1157
     * from geometry provided in viewport CRS
1158
     * 
1159
     * @param lyr
1160
     * @param geo
1161
     * @param clone
1162
     * @return
1163
     * @deprecated use the transformToSourceCRS method of layer.
1164
     */
1165
    public static Geometry fromViewPortCRSToSourceCRS(
1166
        FLayer lyr,
1167
        Geometry geo,
1168
        boolean clone) {
1169
        
1170
        if (lyr == null || geo == null) {
1171
            return null;
1172
        }
1173
        ICoordTrans ct = lyr.getCoordTrans();
1174
        Geometry resp = geo;
1175
        if (clone) {
1176
            resp = resp.cloneGeometry();
1177
        }
1178
        if (ct != null) {
1179
            resp.reProject(ct.getInverted());
1180
        }
1181
        return resp;
1182
    }
1183

    
1184
    
1185
}