Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.daltransform.app / org.gvsig.daltransform.app.eventtheme / src / main / java / org / gvsig / app / eventtheme / dal / feature / EventThemeTransform.java @ 41610

History | View | Annotate | Download (17.1 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
/*
25
 * AUTHORS (In addition to CIT):
26
 * 2009 {Iver T.I.}   {Task}
27
 */
28

    
29
package org.gvsig.app.eventtheme.dal.feature;
30

    
31
import java.util.Arrays;
32

    
33
import javax.swing.JOptionPane;
34

    
35
import org.cresques.cts.IProjection;
36

    
37
import org.gvsig.app.ApplicationLocator;
38
import org.gvsig.fmap.dal.DataStore;
39
import org.gvsig.fmap.dal.DataTypes;
40
import org.gvsig.fmap.dal.exception.DataException;
41
import org.gvsig.fmap.dal.exception.InitializeException;
42
import org.gvsig.fmap.dal.feature.AbstractFeatureStoreTransform;
43
import org.gvsig.fmap.dal.feature.EditableFeature;
44
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
45
import org.gvsig.fmap.dal.feature.EditableFeatureType;
46
import org.gvsig.fmap.dal.feature.Feature;
47
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
48
import org.gvsig.fmap.dal.feature.FeatureSet;
49
import org.gvsig.fmap.dal.feature.FeatureStore;
50
import org.gvsig.fmap.dal.feature.FeatureType;
51
import org.gvsig.fmap.dal.feature.exception.SetReadOnlyAttributeException;
52
import org.gvsig.fmap.geom.Geometry;
53
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
54
import org.gvsig.fmap.geom.Geometry.TYPES;
55
import org.gvsig.fmap.geom.GeometryLocator;
56
import org.gvsig.fmap.geom.GeometryManager;
57
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
58
import org.gvsig.fmap.geom.exception.CreateGeometryException;
59
import org.gvsig.fmap.geom.primitive.Envelope;
60
import org.gvsig.fmap.geom.primitive.Point;
61
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
62
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
63
import org.gvsig.i18n.Messages;
64
import org.gvsig.tools.ToolsLocator;
65
import org.gvsig.tools.dispose.DisposableIterator;
66
import org.gvsig.tools.dynobject.DynStruct;
67
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
68
import org.gvsig.tools.persistence.PersistenceManager;
69
import org.gvsig.tools.persistence.PersistentState;
70
import org.gvsig.tools.persistence.exception.PersistenceException;
71
import org.gvsig.tools.task.AbstractMonitorableTask;
72
import org.gvsig.tools.task.TaskStatusManager;
73
import org.slf4j.Logger;
74
import org.slf4j.LoggerFactory;
75

    
76
/**
77
 * This class implements a transformation for a events theme. The original 
78
 * {@link DataStore} have to have a couple of attributes, one with the X 
79
 * coordinate and the second one with the Y coordinate. The result of 
80
 * the transformation is a {@link DataStore} that has a new geometric 
81
 * attribute and its value is a point with the coordinates specified in 
82
 * the original {@link DataStore}. 
83
 * @author <a href="mailto:jpiera@gvsig.org">Jorge Piera</a>
84
 */
85
public class EventThemeTransform extends AbstractFeatureStoreTransform {
86

    
87
        private static Logger logger = LoggerFactory.getLogger(
88
                        EventThemeTransform.class);
89
        
90
    public static final String PERSISTENCE_DEFINITION_NAME = "EventThemeTransform";
91
    /**
92
     * Max number of features used for initial estimation
93
     * of extent. Many other features will be ignored
94
     * simply with "iter.next()"
95
     */
96
    public static int MAX_INI_FEATURES = 200;
97

    
98
    private String xFieldName = null;
99
    private String yFieldName = null;
100
    private String geometryFieldName = null;
101
    private IProjection projection = null;
102
    private FeatureType originalFeatureType;
103
    private GeometryManager geometryManager = GeometryLocator.getGeometryManager();    
104
    private Envelope envelope;
105

    
106
    public EventThemeTransform() {
107
        super();
108
        geometryManager = GeometryLocator.getGeometryManager();
109
    }
110

    
111
    /**
112
     * This method initializes the transformation, sets the name of the parameters and 
113
     * sets the value of the {@link FeatureType} returned by the transformation. 
114
     * @param store
115
     * The original store. 
116
     * @param geometryFieldName
117
     * The field that contains the geometric attribute.
118
     * @param xFieldName
119
     * The field that contains the X coordinate.
120
     * @param yFieldName
121
     * The field that contains the Y coordinate.
122
     * @throws DataException
123
     */
124
    public void initialize(
125
                    FeatureStore store,
126
                    String geometryFieldName,
127
                    String xFieldName,
128
                    String yFieldName,
129
                    IProjection projection) throws DataException{
130
            
131
        setFeatureStore(store);
132
        this.xFieldName = xFieldName;
133
        this.yFieldName = yFieldName;
134
        this.projection = projection;
135
        if ((geometryFieldName == null) || (geometryFieldName.equals(""))){
136
            this.geometryFieldName = "the_geom";
137
        }else{
138
            this.geometryFieldName = geometryFieldName;
139
        }
140
        this.originalFeatureType = this.getFeatureStore()
141
        .getDefaultFeatureType();
142

    
143
        EditableFeatureType type = originalFeatureType.getEditable();
144
        if (type.get(this.geometryFieldName) == null){
145
            EditableFeatureAttributeDescriptor attributeDescriptor = type.add(this.geometryFieldName,  DataTypes.GEOMETRY);
146
            try {
147
                attributeDescriptor.setGeometryType(geometryManager.getGeometryType(TYPES.POINT, SUBTYPES.GEOM2D));
148
            } catch (GeometryTypeNotSupportedException e) {
149
                throw new InitializeException(e);
150
            } catch (GeometryTypeNotValidException e) {
151
                throw new InitializeException(e);
152
            }           
153
            attributeDescriptor.setSRS(projection);
154
        }
155

    
156
        try {
157
            /*
158
             * creates and updates envelope with all features
159
             */
160
            initEnvelope(store, MAX_INI_FEATURES);
161
        } catch (CreateEnvelopeException e) {
162
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
163
        }
164

    
165
        type.setDefaultGeometryAttributeName(this.geometryFieldName);
166
        FeatureType[] types = new FeatureType[] { type.getNotEditableCopy() };
167
        setFeatureTypes(Arrays.asList(types), types[0]);
168
    }
169
    
170
    
171

    
172
    /**
173
     * creates and updates envelope with all features
174
     * 
175
     */
176
    private void initEnvelope(FeatureStore fsto, int max_feats) throws CreateEnvelopeException {
177
        
178
        envelope = geometryManager.createEnvelope(SUBTYPES.GEOM2D);
179
        FeatureSet fset = null;
180
        DisposableIterator diter = null;
181
        Feature feat = null;
182
        try {
183
            fset = fsto.getFeatureSet();
184
            diter = fset.fastIterator();
185
            
186
            // int count = 0;
187
            int countused = 0;
188
            int nextwait = 1;
189
            int index = 0;
190
            
191
            while (diter.hasNext() && (countused < max_feats)) {
192
                    
193
                feat = (Feature) diter.next();
194
                /*
195
                 * This loop will use about 70 features from the first
196
                 * 3000 features, more and more separated each time.
197
                 * Something like:
198
                 * 
199
                 * 1st, 2nd ,3rd, 5th, 8th, 15, 25, 40, 100, 300...
200
                 * 
201
                 * Other features are ignored with diter.next().
202
                 * That causes an acceptable behavior even if the store
203
                 * is very large.
204
                 * 
205
                 * Afterwards, the extent is updated while drawing,
206
                 * so it's not very important.
207
                 */
208
                index++;
209
                if (index == nextwait) {
210
                        index = 0;
211
                        /*
212
                         * This causes that the first 5 features
213
                         * will always be used.
214
                         */
215
                        if (countused > 5) {
216
                            nextwait++;
217
                        }
218
                        this.updateEnvelope(feat);
219
                        countused++;
220
                }
221
                // count++;
222
            }
223
            
224
            diter.dispose();
225
            
226
        } catch (Exception dex) {
227
            throw new CreateEnvelopeException(SUBTYPES.GEOM2D, dex);
228
        }
229
    }
230
    
231
    public void setEnvelope(Envelope env) {
232
            this.envelope = env;
233
    }
234

    
235
    /*
236
     * Currently not used
237
     */
238
    private void launchFullExtentThread(DisposableIterator diter) {
239
            
240
            ComputeExtentTask task = new ComputeExtentTask(diter, this);
241
            task.start();
242
        }
243

    
244
        /* (non-Javadoc)
245
     * @see org.gvsig.fmap.dal.feature.FeatureStoreTransform#applyTransform(org.gvsig.fmap.dal.feature.Feature, org.gvsig.fmap.dal.feature.EditableFeature)
246
     */
247
    public void applyTransform(Feature source, EditableFeature target)
248
    throws DataException {
249
        
250
        this.copySourceToTarget(source, target);
251

    
252
        try {
253
            
254
            Geometry point = null;
255
            Object xval = source.get(xFieldName);
256
            Object yval = source.get(yFieldName);
257
            if (xval == null || yval == null) {
258
                logger.info("Found row with null coordinates in event theme (created null geometry)");
259
                target.set(geometryFieldName, null);
260
                target.setDefaultGeometry(null);  
261
            } else {
262
                point = geometryManager.createPoint(
263
                    new Double(xval.toString()),
264
                    new Double(yval.toString()),
265
                    SUBTYPES.GEOM2D);
266
                target.set(geometryFieldName, point);
267
                target.setDefaultGeometry(point);   
268
                envelope.add(point.getEnvelope());
269
            }
270
        } catch ( SetReadOnlyAttributeException e1) {            
271
            // Do nothing
272
            
273
        } catch (Exception e) {
274
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(
275
                TYPES.POINT, SUBTYPES.GEOM2D, e);
276
        }       
277
        
278
    }
279
    
280
    /**
281
     * Used internally to initialize envelope
282
     * 
283
     */
284
    private void updateEnvelope(Feature feat) throws CreateGeometryException {
285

    
286
        Point point = geometryManager.createPoint(
287
            new Double(feat.get(xFieldName).toString()),
288
            new Double(feat.get(yFieldName).toString()),
289
            SUBTYPES.GEOM2D);
290
        envelope.add(point.getEnvelope());
291
    }
292

    
293
    /**
294
     * @param source
295
     * @param target
296
     */
297
    private void copySourceToTarget(Feature source, EditableFeature target) {
298
        FeatureAttributeDescriptor attr, attrTrg;
299
        FeatureType ftSrc = source.getType();
300
        FeatureType ftTrg = target.getType();
301

    
302

    
303
        for (int i = 0; i < source.getType().size(); i++) {
304
            attr = ftSrc.getAttributeDescriptor(i);
305
            if (ftTrg.getIndex(attr.getName()) > -1) {
306
                try {
307
                    target.set(attr.getName(), source.get(i));
308
                } catch (IllegalArgumentException e) {
309
                    attrTrg = ftTrg.getAttributeDescriptor(attr.getName());
310
                    target.set(attrTrg.getIndex(), attrTrg.getDefaultValue());
311
                }
312

    
313
            }
314
        }
315

    
316
    }
317

    
318
    /* (non-Javadoc)
319
     * @see org.gvsig.fmap.dal.feature.FeatureStoreTransform#getSourceFeatureTypeFrom(org.gvsig.fmap.dal.feature.FeatureType)
320
     */
321
    public FeatureType getSourceFeatureTypeFrom(FeatureType targetFeatureType) {
322
        return this.originalFeatureType;
323
    }
324

    
325
    /* (non-Javadoc)
326
     * @see org.gvsig.fmap.dal.feature.FeatureStoreTransform#isTransformsOriginalValues()
327
     */
328
    public boolean isTransformsOriginalValues() {
329
        return true;
330
    }
331

    
332
    public static void registerPersistent() {
333
        PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
334

    
335
        if( persistenceManager.getDefinition(AbstractFeatureStoreTransform.class) == null ) {
336
            AbstractFeatureStoreTransform.registerPersistent();
337
        }
338

    
339
        DynStruct definition = persistenceManager.getDefinition(PERSISTENCE_DEFINITION_NAME);
340

    
341
        if (definition == null){           
342
            definition = persistenceManager.addDefinition(
343
                EventThemeTransform.class,
344
                PERSISTENCE_DEFINITION_NAME,
345
                "EventThemeTransform Persistence definition",
346
                null, 
347
                null
348
            );
349
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
350
                ABSTRACT_FEATURESTORE_DYNCLASS_NAME);
351

    
352
            definition.addDynFieldString("geometryFieldName").setMandatory(true);
353
            definition.addDynFieldString("xFieldName").setMandatory(true);
354
            definition.addDynFieldString("yFieldName").setMandatory(true);
355
            definition.addDynFieldObject("projection").setType(DataTypes.CRS);
356
        }
357
    }
358

    
359
    /* (non-Javadoc)
360
     * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
361
     */
362
    public void saveToState(PersistentState state) throws PersistenceException {
363
        super.saveToState(state);
364
        state.set("geometryFieldName", this.geometryFieldName);
365
        state.set("xFieldName", this.xFieldName);
366
        state.set("yFieldName", this.yFieldName);
367
        state.set("projection", this.projection);                
368
    }
369

    
370
    /* (non-Javadoc)
371
     * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
372
     */
373
    public void loadFromState(PersistentState state)
374
    throws PersistenceException {
375
        super.loadFromState(state);                
376
        String geometryFieldName = state.getString("geometryFieldName");
377
        String xFieldName = state.getString("xFieldName");
378
        String yFieldName = state.getString("yFieldName");
379
        IProjection projection =  (IProjection)state.get("projection");        
380
        try {
381
            initialize(getFeatureStore(), geometryFieldName, xFieldName, yFieldName, projection);
382
        } catch (DataException e) {
383
            throw new PersistenceException("Impossible to create the transform", e);
384
        }
385
    }
386

    
387
    public Object getDynValue(String name) throws DynFieldNotFoundException {
388
        if (DataStore.METADATA_CRS.equals(name)){
389
            return projection;
390
        }else if(DataStore.METADATA_ENVELOPE.equals(name)){
391
            return envelope;
392
        }
393
        return null;
394
    }
395

    
396
    public boolean hasDynValue(String name) {
397
        return ((DataStore.METADATA_CRS.equals(name)) || 
398
            (DataStore.METADATA_ENVELOPE.equals(name)));
399
    }    
400
    
401
    
402
    /**
403
     * 
404
     * A thread to compute the true extent (in case it has a lot of features)
405
     * Currently not used.
406
     * 
407
     * @author jldominguez
408
     * 
409
     * @deprecated This is not used because it causes issues with
410
     * ConsurrentModificationException because the store is notified of
411
     * a change (the transformation). Anyway, this is not very important I think.
412
     */
413
    private class ComputeExtentTask extends AbstractMonitorableTask {
414
            
415
            private DisposableIterator disp_iter = null;
416
            private EventThemeTransform tra_toupdate = null;
417
            
418
            public ComputeExtentTask(DisposableIterator diter, EventThemeTransform ettra) {
419
                    /*
420
                     * Auto-added by task manager
421
                     */
422
                    super(Messages.getText("_Extent_of_event_theme"), true);
423
                    disp_iter = diter;
424
                    tra_toupdate = ettra;
425
            }
426
            
427
            public void run() {
428

    
429
                    Envelope env = null;
430
                    Feature feat = null;
431
                    Point point = null;
432
                    int count = 99;
433
                    
434
                    try {
435
                while (disp_iter.hasNext()) {
436
                    feat = (Feature) disp_iter.next();
437
                    point = geometryManager.createPoint(
438
                            Double.parseDouble(feat.get(xFieldName).toString()),
439
                            Double.parseDouble(feat.get(yFieldName).toString()),
440
                            SUBTYPES.GEOM2D);
441
                    if (env == null) {
442
                            env = (Envelope) point.getEnvelope().clone();
443
                    } else {
444
                            env.add(point.getEnvelope());
445
                    }
446
                    count++;
447
                    Thread.sleep(10);
448
                    if (count % 100 == 0) {
449
                            System.out.println("COUNT = " + count);
450
                    }
451
                }
452
                    } catch (Exception exc) {
453
                            
454
                            ApplicationLocator.getManager().message(
455
                                            Messages.getText("_Error_while_getting_extent"),
456
                                            JOptionPane.ERROR_MESSAGE);
457
                            logger.info("Error while getting extent in thread.", exc);
458
                            
459
                    }
460
                    
461
                    disp_iter.dispose();
462
                    // =================
463
                    if (env != null) {
464
                            Envelope curr_env = (Envelope) tra_toupdate.getDynValue(
465
                                            DataStore.METADATA_ENVELOPE); 
466
                            curr_env.add(env);
467
                    }
468
                    // =========== End
469
                    TaskStatusManager man = this.getTaskStatus().getManager();
470
                    man.remove(this.getTaskStatus());
471
            }
472
            
473
    }
474
}
475