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

History | View | Annotate | Download (38.4 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.Iterator;
32
import java.util.List;
33
import java.util.Set;
34
import java.util.TreeSet;
35

    
36
import org.cresques.cts.ICoordTrans;
37
import org.cresques.cts.IProjection;
38
import org.slf4j.LoggerFactory;
39

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

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

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

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

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

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

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

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

    
143
    /**
144
     * Devuelve el VectorialAdapater de la capa.
145
     * 
146
     * @return VectorialAdapter.
147
     */
148
    public DataStore getDataStore() {
149
        if (!this.isAvailable()) {
150
            return null;
151
        }
152
        return featureStore;
153
    }
154
    
155
    /**
156
     * Asigna el data-store a la capa.
157
     * Esta operacion no se deneria poder hacer desde fuera de la clase.
158
     * 
159
     * @param dataStore
160
     * @throws LoadLayerException
161
     * @deprecated use {@link #bindToDataStore(DataStore)}
162
     */
163
    public void setDataStore(DataStore dataStore) throws LoadLayerException {
164
            bindToDataStore(dataStore);
165
    }
166
    
167
    /**
168
     * Enlaza la capa con el DataStore indicado.
169
     *  
170
     * @param dataStore
171
     * @throws LoadLayerException
172
     */
173
    protected void bindToDataStore(DataStore dataStore) throws LoadLayerException {
174
        if (this.featureStore != null && this.featureStore != dataStore) {
175
            this.featureStore.deleteObserver(this);
176
        }
177

    
178
        featureStore = (FeatureStore) dataStore;
179

    
180
        MapContextManager mapContextManager =
181
            MapContextLocator.getMapContextManager();
182
        
183
        //Set the legend
184
        IVectorLegend legend =
185
            (IVectorLegend)mapContextManager.getLegend(dataStore);
186

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

    
191
        this.setLegend(legend);
192

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

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

    
204
        this.delegate(dataStore);
205

    
206
        dataStore.addObserver(this);
207

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

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

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

    
238
    }
239

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

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

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

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

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

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

    
289
        try {
290
            
291
            long tini = System.currentTimeMillis();
292
            
293
            legend.draw(image,
294
                g,
295
                viewPort,
296
                cancel,
297
                scale,
298
                null,
299
                getCoordTrans(),
300
                getFeatureStore(),
301
                featureQuery);
302
            
303
            logger.debug("Layer " + this.getName() + " drawn in " +
304
                (System.currentTimeMillis() - tini) + " milliseconds.");
305

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

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

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

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

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

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

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

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

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

    
424
        if (!this.isAvailable()) {
425
            return;
426
        }
427

    
428
        super.saveToState(state);
429

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

    
434
        FeatureStore fst = null;
435
        fst = getFeatureStore();
436

    
437
        if (fst != null) {
438
            state.set("featureStore", fst);
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("bHasJoin", bHasJoin);
452
        state.set("typeShape", typeShape);
453
    }
454

    
455

    
456
    public void loadFromState(PersistentState state) throws PersistenceException {
457

    
458
        super.loadFromState(state);
459
        DataStore store = null;
460
        try {
461
                store = (DataStore) state.get("featureStore");
462
        } catch (PersistenceRuntimeException e) {
463
            logger.debug("Unable to load store from persistence in layer: " + this.getName(), e);
464
                        this.setAvailable(false);
465
                        return;
466
                }
467
        try {
468
            this.bindToDataStore(store);
469
        } catch (LoadLayerException e) {
470
            throw new PersistenceException("While loading FLyrVect from state.",
471
                e);
472
        }
473

    
474
        IVectorLegend lgnd = (IVectorLegend) state.get("legend");
475
        try {
476
            this.setLegend(lgnd);
477
        } catch (LegendLayerException e) {
478
            throw new PersistenceException("While loading FLyrVect from state.",
479
                e);
480
        }
481

    
482
        Boolean isLbl = new Boolean(false);
483
        ILabelingStrategy lblst = null;
484

    
485
        try {
486
            isLbl = (Boolean) state.get("isLabeled");
487
            if (isLbl.booleanValue()) {
488
                lblst = (ILabelingStrategy) state.get("labelingStrategy");
489
            }
490
        } catch (Exception ex) {
491
            throw new PersistenceException("While loading FLyrVect from state.",
492
                ex);
493
        }
494

    
495
        /*
496
         * String _labelFieldName = null;
497
         * String _labelfield = null;
498
         */
499

    
500
        if (isLbl.booleanValue()) {
501
            this.setIsLabeled(true);
502
            this.setLabelingStrategy(lblst);
503
        } else {
504
            this.setIsLabeled(false);
505
            this.setLabelingStrategy(null);
506
        }
507

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

    
510
    }
511

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

    
525
        return "layer" + ret.substring(ret.indexOf('@') + 1);
526
    }
527

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

    
567

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

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

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

    
589
    public SpatialCache getSpatialCache() {
590
        return spatialCache;
591
    }
592

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

    
603
    }
604

    
605
    /**
606
     * This method returns a boolean that is used by the FPopMenu
607
     * to make visible the properties menu or not. It is visible by
608
     * default, and if a later don't have to show this menu only
609
     * has to override this method.
610
     * 
611
     * @return
612
     *         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

    
709
            // Se supone que la geometria ya esta reproyectada
710
            // if (ct!=null) {
711
            // // geomBounds = ct.getInverted().convert(geomBounds);
712
            // geomBounds = geomBounds.convert(ct);
713
            // }
714

    
715
            double dist1Pixel = viewPort.getDist1pixel();
716

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

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

    
736
            }
737

    
738
        }
739
        return onePoint;
740
    }
741

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

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

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

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

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

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

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

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

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

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

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

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

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

    
870
    }
871

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

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

    
927
    }
928

    
929
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
930
        DataException {
931

    
932
        return getInfo(p, tolerance, cancel, true);
933
    }
934

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

    
946
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
947
        double tolerance) throws LoadLayerException, DataException {
948
        return queryByPoint(p,tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
949
    }
950
    
951
    public void legendCleared(LegendClearEvent event) {
952
        this.updateDrawVersion();
953
        LegendChangedEvent e =
954
            LegendChangedEvent.createLegendChangedEvent(legend, legend);
955
        this.callLegendChanged(e);
956
    }
957

    
958
    public boolean symbolChanged(SymbolLegendEvent e) {
959
        this.updateDrawVersion();
960
        LegendChangedEvent ev =
961
            LegendChangedEvent.createLegendChangedEvent(legend, legend);
962
        this.callLegendChanged(ev);
963
        return true;
964
    }
965

    
966
    public void update(Observable observable, Object notification) {
967
        if (observable.equals(this.featureStore)) {
968
            if (notification instanceof FeatureStoreNotification) {
969
                FeatureStoreNotification event =
970
                    (FeatureStoreNotification) notification;
971
                if (event.getType() == FeatureStoreNotification.AFTER_DELETE
972
                    || event.getType() == FeatureStoreNotification.AFTER_UNDO
973
                    || event.getType() == FeatureStoreNotification.AFTER_REDO
974
                    || event.getType() == FeatureStoreNotification.AFTER_REFRESH
975
                    || event.getType() == FeatureStoreNotification.AFTER_UPDATE
976
                    || event.getType() == FeatureStoreNotification.AFTER_UPDATE_TYPE
977
                    || event.getType() == FeatureStoreNotification.SELECTION_CHANGE
978
                    || event.getType() == FeatureStoreNotification.AFTER_INSERT) {
979
                    this.updateDrawVersion();
980
                    
981
                } else if (event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING) {
982
                    
983
                    setSpatialCacheEnabled(false);
984
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
985
                    this.updateDrawVersion();
986
                    
987
                } else if (event.getType() == FeatureStoreNotification.AFTER_STARTEDITING) {
988
                    
989
                    setSpatialCacheEnabled(true);
990
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
991

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

    
1020
    private boolean isLayerToSnap() {
1021
            
1022
            boolean resp = this.getMapContext().getLayersToSnap().contains(this);
1023
            return resp;
1024
            
1025
            /*
1026
            Iterator itersnap = this.getMapContext().getLayersToSnap().iterator();
1027
            Object item = null;
1028
            while (itersnap.hasNext()) {
1029
                    item = itersnap.next();
1030
                    if (item == this) {
1031
                            return true;
1032
                    }
1033
            }
1034
                return false;
1035
                */
1036
        }
1037

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

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

    
1059
    
1060

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

    
1077
    public static void registerPersistent() {
1078
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1079
        if (manager.getDefinition(FLyrDefault.class) == null) {
1080
            FLyrDefault.registerPersistent();
1081
        }
1082
        DynStruct definition =
1083
            manager.addDefinition(FLyrVect.class,
1084
                "FLyrVect",
1085
                "FLyrVect Persistence definition",
1086
                null,
1087
                null);
1088
        definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1089
            "FLyrDefault");
1090

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

    
1103
    }
1104

    
1105
    protected void doDispose() throws BaseException {
1106
        dispose(featureStore);
1107
        spatialCache.clearAll();
1108
    }
1109
    
1110
    /**
1111
     * Returns envelope in layer's data source CRS
1112
     * from envelope provided in viewport CRS
1113
     * 
1114
     * @param lyr
1115
     * @param env
1116
     * @return
1117
     */
1118
    public static Envelope fromViewPortCRSToSourceCRS(FLayer lyr, Envelope env) {
1119

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

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

    
1132
    /**
1133
     * Returns geometry in layer's data source CRS
1134
     * from geometry provided in viewport CRS
1135
     * 
1136
     * @param lyr
1137
     * @param geo
1138
     * @param clone
1139
     * @return
1140
     */
1141
    public static Geometry fromViewPortCRSToSourceCRS(
1142
        FLayer lyr,
1143
        Geometry geo,
1144
        boolean clone) {
1145
        
1146
        if (lyr == null || geo == null) {
1147
            return null;
1148
        }
1149
        ICoordTrans ct = lyr.getCoordTrans();
1150
        Geometry resp = geo;
1151
        if (clone) {
1152
            resp = resp.cloneGeometry();
1153
        }
1154
        if (ct != null) {
1155
            resp.reProject(ct.getInverted());
1156
        }
1157
        return resp;
1158
    }
1159

    
1160
    
1161
}