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

History | View | Annotate | Download (17.2 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.TaskStatus;
73
import org.gvsig.tools.task.TaskStatusManager;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
304

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

    
315
            }
316
        }
317

    
318
    }
319

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

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

    
334
    public static void registerPersistent() {
335
        PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
336

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

    
341
        DynStruct definition = persistenceManager.getDefinition(PERSISTENCE_DEFINITION_NAME);
342

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

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

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

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

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

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

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