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 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40559 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5 40435 jjdelcerro
 *
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 40559 jjdelcerro
 * as published by the Free Software Foundation; either version 3
9 40435 jjdelcerro
 * 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 40559 jjdelcerro
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20 40435 jjdelcerro
 *
21 40559 jjdelcerro
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23 40435 jjdelcerro
 */
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 41840 jjdelcerro
import org.gvsig.tools.util.Callable;
95 40435 jjdelcerro
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 41807 jjdelcerro
        FeatureStore featureStore = null;
424
425
        if ( !this.isAvailable() ) {
426
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
427 40435 jjdelcerro
            return;
428
        }
429 41807 jjdelcerro
430
        try {
431
            super.saveToState(state);
432 40435 jjdelcerro
433 41807 jjdelcerro
            if ( getLegend() != null ) {
434
                state.set("legend", getLegend());
435
            }
436 40435 jjdelcerro
437 41807 jjdelcerro
            featureStore = getFeatureStore();
438 40435 jjdelcerro
439 41807 jjdelcerro
            if ( featureStore != null ) {
440
                state.set("featureStore", featureStore);
441
            }
442 40435 jjdelcerro
443 41807 jjdelcerro
            state.set("isLabeled", isLabeled);
444 40435 jjdelcerro
445 41807 jjdelcerro
            if ( strategy != null ) {
446
                state.set("labelingStrategy", strategy);
447
            }
448 40435 jjdelcerro
449 41807 jjdelcerro
            if ( getLinkProperties() != null ) {
450
                state.set("linkProperties", getLinkProperties());
451
            }
452 40435 jjdelcerro
453 41807 jjdelcerro
            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 40435 jjdelcerro
        }
461
462
    }
463
464
465
    public void loadFromState(PersistentState state) throws PersistenceException {
466
467
        DataStore store = null;
468 41807 jjdelcerro
        IVectorLegend vectorLegend = null;
469
        ILabelingStrategy labelingStrategy = null;
470
        Boolean isLabeled = Boolean.FALSE;
471 41146 jldominguez
472 40435 jjdelcerro
        try {
473 41807 jjdelcerro
                super.loadFromState(state);
474
                store = (DataStore) state.get("featureStore");
475 40435 jjdelcerro
476 41807 jjdelcerro
            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 40435 jjdelcerro
482 41807 jjdelcerro
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 40435 jjdelcerro
            }
490
491
492 41807 jjdelcerro
            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 40435 jjdelcerro
502 41807 jjdelcerro
            if ( isLabeled.booleanValue() ) {
503
                this.setIsLabeled(true);
504
                this.setLabelingStrategy(labelingStrategy);
505
            } else {
506
                this.setIsLabeled(false);
507
                this.setLabelingStrategy(null);
508
            }
509 40435 jjdelcerro
510 41807 jjdelcerro
            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 40435 jjdelcerro
    }
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 41676 jjdelcerro
            strategy.draw(image, g, scale, viewPort, cancel, dpi);
780 40435 jjdelcerro
        }
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 41676 jjdelcerro
            strategy.print(g, scale, viewPort, cancel, properties);
790 40435 jjdelcerro
        }
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 40941 jldominguez
    /**
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 40435 jjdelcerro
    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 41813 jjdelcerro
        Geometry query_geo = this.transformToSourceCRS(geom, true);
864 40435 jjdelcerro
        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 41676 jjdelcerro
        String geomName = featureStore.getDefaultFeatureType()
920 40435 jjdelcerro
                .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 41132 jldominguez
                        logger.info("While reloading layer.", e);
1007 40435 jjdelcerro
                        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 40614 jldominguez
            && (isEditing() || isLayerToSnap())) {
1021
            // This code is needed in editing mode
1022
                // for all layers involved in snapping
1023
                // (including the layer being edited)
1024 40435 jjdelcerro
            Geometry geometry =
1025
                ((FeatureDrawnNotification) notification).getDrawnGeometry();
1026
            spatialCache.insert(geometry.getEnvelope(), geometry);
1027
        }
1028
    }
1029
1030 40614 jldominguez
    private boolean isLayerToSnap() {
1031 41223 jldominguez
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 40614 jldominguez
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 40435 jjdelcerro
     * (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 41840 jjdelcerro
    public static class RegisterPersistence implements Callable {
1094 40435 jjdelcerro
1095 41840 jjdelcerro
        public Object call() {
1096
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1097 40435 jjdelcerro
1098 41840 jjdelcerro
            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 40435 jjdelcerro
    }
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 41813 jjdelcerro
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1151
        return fromViewPortCRSToSourceCRS(this,geom,clone);
1152
    }
1153
1154
1155 40435 jjdelcerro
    /**
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 41813 jjdelcerro
     * @deprecated use the transformToSourceCRS method of layer.
1164 40435 jjdelcerro
     */
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
}