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

History | View | Annotate | Download (16.5 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.geom.Geometry.SUBTYPES;
52
import org.gvsig.fmap.geom.Geometry.TYPES;
53
import org.gvsig.fmap.geom.GeometryLocator;
54
import org.gvsig.fmap.geom.GeometryManager;
55
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
56
import org.gvsig.fmap.geom.exception.CreateGeometryException;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.geom.primitive.Point;
59
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
60
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
61
import org.gvsig.i18n.Messages;
62
import org.gvsig.tools.ToolsLocator;
63
import org.gvsig.tools.dispose.DisposableIterator;
64
import org.gvsig.tools.dynobject.DynStruct;
65
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
66
import org.gvsig.tools.persistence.PersistenceManager;
67
import org.gvsig.tools.persistence.PersistentState;
68
import org.gvsig.tools.persistence.exception.PersistenceException;
69
import org.gvsig.tools.task.AbstractMonitorableTask;
70
import org.gvsig.tools.task.TaskStatus;
71
import org.gvsig.tools.task.TaskStatusManager;
72
import org.slf4j.Logger;
73
import org.slf4j.LoggerFactory;
74

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

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

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

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

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

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

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

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

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

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

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

    
251
        try {           
252
            Point point = geometryManager.createPoint(
253
                new Double(source.get(xFieldName).toString()),
254
                new Double(source.get(yFieldName).toString()),
255
                SUBTYPES.GEOM2D);
256
            target.set(geometryFieldName, point);
257
            target.setDefaultGeometry(point);   
258
            envelope.add(point.getEnvelope());
259
        } catch (CreateGeometryException e) {
260
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(TYPES.POINT, SUBTYPES.GEOM2D, e);
261
        }       
262
        
263
    }
264
    
265
    /**
266
     * Used internally to initialize envelope
267
     * 
268
     */
269
    private void updateEnvelope(Feature feat) throws CreateGeometryException {
270

    
271
        Point point = geometryManager.createPoint(
272
            new Double(feat.get(xFieldName).toString()),
273
            new Double(feat.get(yFieldName).toString()),
274
            SUBTYPES.GEOM2D);
275
        envelope.add(point.getEnvelope());
276
    }
277

    
278
    /**
279
     * @param source
280
     * @param target
281
     */
282
    private void copySourceToTarget(Feature source, EditableFeature target) {
283
        FeatureAttributeDescriptor attr, attrTrg;
284
        FeatureType ftSrc = source.getType();
285
        FeatureType ftTrg = target.getType();
286

    
287

    
288
        for (int i = 0; i < source.getType().size(); i++) {
289
            attr = ftSrc.getAttributeDescriptor(i);
290
            if (ftTrg.getIndex(attr.getName()) > -1) {
291
                try {
292
                    target.set(attr.getName(), source.get(i));
293
                } catch (IllegalArgumentException e) {
294
                    attrTrg = ftTrg.getAttributeDescriptor(attr.getName());
295
                    target.set(attrTrg.getIndex(), attrTrg.getDefaultValue());
296
                }
297

    
298
            }
299
        }
300

    
301
    }
302

    
303
    /* (non-Javadoc)
304
     * @see org.gvsig.fmap.dal.feature.FeatureStoreTransform#getSourceFeatureTypeFrom(org.gvsig.fmap.dal.feature.FeatureType)
305
     */
306
    public FeatureType getSourceFeatureTypeFrom(FeatureType targetFeatureType) {
307
        return this.originalFeatureType;
308
    }
309

    
310
    /* (non-Javadoc)
311
     * @see org.gvsig.fmap.dal.feature.FeatureStoreTransform#isTransformsOriginalValues()
312
     */
313
    public boolean isTransformsOriginalValues() {
314
        return true;
315
    }
316

    
317
    public static void registerPersistent() {
318
        PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
319

    
320
        if( persistenceManager.getDefinition(AbstractFeatureStoreTransform.class) == null ) {
321
            AbstractFeatureStoreTransform.registerPersistent();
322
        }
323

    
324
        DynStruct definition = persistenceManager.getDefinition(PERSISTENCE_DEFINITION_NAME);
325

    
326
        if (definition == null){           
327
            definition = persistenceManager.addDefinition(
328
                EventThemeTransform.class,
329
                PERSISTENCE_DEFINITION_NAME,
330
                "EventThemeTransform Persistence definition",
331
                null, 
332
                null
333
            );
334
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
335
                ABSTRACT_FEATURESTORE_DYNCLASS_NAME);
336

    
337
            definition.addDynFieldString("geometryFieldName").setMandatory(true);
338
            definition.addDynFieldString("xFieldName").setMandatory(true);
339
            definition.addDynFieldString("yFieldName").setMandatory(true);
340
            definition.addDynFieldObject("projection").setType(DataTypes.CRS);
341
        }
342
    }
343

    
344
    /* (non-Javadoc)
345
     * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
346
     */
347
    public void saveToState(PersistentState state) throws PersistenceException {
348
        super.saveToState(state);
349
        state.set("geometryFieldName", this.geometryFieldName);
350
        state.set("xFieldName", this.xFieldName);
351
        state.set("yFieldName", this.yFieldName);
352
        state.set("projection", this.projection);                
353
    }
354

    
355
    /* (non-Javadoc)
356
     * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
357
     */
358
    public void loadFromState(PersistentState state)
359
    throws PersistenceException {
360
        super.loadFromState(state);                
361
        String geometryFieldName = state.getString("geometryFieldName");
362
        String xFieldName = state.getString("xFieldName");
363
        String yFieldName = state.getString("yFieldName");
364
        IProjection projection =  (IProjection)state.get("projection");        
365
        try {
366
            initialize(getFeatureStore(), geometryFieldName, xFieldName, yFieldName, projection);
367
        } catch (DataException e) {
368
            throw new PersistenceException("Impossible to create the transform", e);
369
        }
370
    }
371

    
372
    public Object getDynValue(String name) throws DynFieldNotFoundException {
373
        if (DataStore.METADATA_CRS.equals(name)){
374
            return projection;
375
        }else if(DataStore.METADATA_ENVELOPE.equals(name)){
376
            return envelope;
377
        }
378
        return null;
379
    }
380

    
381
    public boolean hasDynValue(String name) {
382
        return ((DataStore.METADATA_CRS.equals(name)) || 
383
            (DataStore.METADATA_ENVELOPE.equals(name)));
384
    }    
385
    
386
    
387
    /**
388
     * 
389
     * A thread to compute the true extent (in case it has a lot of features)
390
     * Currently not used.
391
     * 
392
     * @author jldominguez
393
     * 
394
     * @deprecated This is not used because it causes issues with
395
     * ConsurrentModificationException because the store is notified of
396
     * a change (the transformation). Anyway, this is not very important I think.
397
     */
398
    private class ComputeExtentTask extends AbstractMonitorableTask {
399
            
400
            private DisposableIterator disp_iter = null;
401
            private EventThemeTransform tra_toupdate = null;
402
            
403
            public ComputeExtentTask(DisposableIterator diter, EventThemeTransform ettra) {
404
                    /*
405
                     * Auto-added by task manager
406
                     */
407
                    super(Messages.getText("_Extent_of_event_theme"), true);
408
                    disp_iter = diter;
409
                    tra_toupdate = ettra;
410
            }
411
            
412
            public void run() {
413

    
414
                    Envelope env = null;
415
                    Feature feat = null;
416
                    Point point = null;
417
                    int count = 99;
418
                    
419
                    try {
420
                while (disp_iter.hasNext()) {
421
                    feat = (Feature) disp_iter.next();
422
                    point = geometryManager.createPoint(
423
                            Double.parseDouble(feat.get(xFieldName).toString()),
424
                            Double.parseDouble(feat.get(yFieldName).toString()),
425
                            SUBTYPES.GEOM2D);
426
                    if (env == null) {
427
                            env = (Envelope) point.getEnvelope().clone();
428
                    } else {
429
                            env.add(point.getEnvelope());
430
                    }
431
                    count++;
432
                    Thread.sleep(10);
433
                    if (count % 100 == 0) {
434
                            System.out.println("COUNT = " + count);
435
                    }
436
                }
437
                    } catch (Exception exc) {
438
                            
439
                            ApplicationLocator.getManager().message(
440
                                            Messages.getText("_Error_while_getting_extent"),
441
                                            JOptionPane.ERROR_MESSAGE);
442
                            logger.info("Error while getting extent in thread.", exc);
443
                            
444
                    }
445
                    
446
                    disp_iter.dispose();
447
                    // =================
448
                    if (env != null) {
449
                            Envelope curr_env = (Envelope) tra_toupdate.getDynValue(
450
                                            DataStore.METADATA_ENVELOPE); 
451
                            curr_env.add(env);
452
                    }
453
                    // =========== End
454
                    TaskStatusManager man = this.getTaskStatus().getManager();
455
                    man.remove(this.getTaskStatus());
456
            }
457
            
458
    }
459
}
460