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

History | View | Annotate | Download (13.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/*
25
 * AUTHORS (In addition to CIT):
26
 * 2009 {Iver T.I.}   {Task}
27
 */
28
package org.gvsig.app.eventtheme.dal.feature;
29

    
30
import java.util.Arrays;
31
import javax.json.JsonObject;
32

    
33
import org.apache.commons.lang3.StringUtils;
34

    
35
import org.cresques.cts.IProjection;
36

    
37
import org.gvsig.fmap.dal.DataStore;
38
import org.gvsig.fmap.dal.DataTypes;
39
import org.gvsig.fmap.dal.exception.DataException;
40
import org.gvsig.fmap.dal.exception.InitializeException;
41
import org.gvsig.fmap.dal.feature.AbstractFeatureStoreTransform;
42
import org.gvsig.fmap.dal.feature.EditableFeature;
43
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
44
import org.gvsig.fmap.dal.feature.EditableFeatureType;
45
import org.gvsig.fmap.dal.feature.Feature;
46
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
47
import org.gvsig.fmap.dal.feature.FeatureSet;
48
import org.gvsig.fmap.dal.feature.FeatureStore;
49
import org.gvsig.fmap.dal.feature.FeatureType;
50
import org.gvsig.fmap.geom.Geometry;
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.json.JsonObjectBuilder;
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.slf4j.Logger;
70
import org.slf4j.LoggerFactory;
71

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

    
85
    private static Logger LOGGER = LoggerFactory.getLogger(EventThemeTransform.class);
86

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

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

    
102
    public EventThemeTransform() {
103
        super();
104
        geometryManager = GeometryLocator.getGeometryManager();
105
    }
106

    
107
    /**
108
     * This method initializes the transformation, sets the name of the
109
     * parameters and sets the value of the {@link FeatureType} returned by the
110
     * transformation.
111
     *
112
     * @param store The original store.
113
     * @param geometryFieldName The field that contains the geometric attribute.
114
     * @param xFieldName The field that contains the X coordinate.
115
     * @param yFieldName The field that contains the Y coordinate.
116
     * @param projection
117
     * @throws DataException
118
     */
119
    public void setValues(
120
        FeatureStore store,
121
        String geometryFieldName,
122
        String xFieldName,
123
        String yFieldName,
124
        IProjection projection) throws DataException {
125

    
126
        setFeatureStore(store);
127
        this.xFieldName = xFieldName;
128
        this.yFieldName = yFieldName;
129
        this.projection = projection;
130
        if( StringUtils.isEmpty(geometryFieldName) ) {
131
            this.geometryFieldName = "the_geom";
132
        } else {
133
            this.geometryFieldName = geometryFieldName;
134
        }
135
    }
136

    
137
    @Override
138
    public void setUp() throws Exception {
139

    
140
        this.originalFeatureType = this.getFeatureStore().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 | GeometryTypeNotValidException e) {
148
                throw new InitializeException(e);
149
            }
150
            attributeDescriptor.setSRS(projection);
151
            attributeDescriptor.setFeatureAttributeEmulator(new FeatureAttributeEmulator() {
152
                @Override
153
                public Object get(Feature feature) {
154
                    Geometry point = null;
155
                    Object xval = feature.get(xFieldName);
156
                    Object yval = feature.get(yFieldName);
157
                    if( xval == null || yval == null ) {
158
                        LOGGER.info("Found row with null coordinates in event theme (created null geometry)");
159
                        return null;
160
                    } else {
161
                        try {
162
                            point = geometryManager.createPoint(
163
                                    new Double(xval.toString()),
164
                                    new Double(yval.toString()),
165
                                    SUBTYPES.GEOM2D);
166
                        } catch (CreateGeometryException ex) {
167
                        }
168
                        return point;
169
                    }
170
                }
171

    
172
                @Override
173
                public void set(EditableFeature feature, Object value) {
174
                    throw new UnsupportedOperationException("Not supported yet.");
175
                }
176

    
177
                @Override
178
                public boolean allowSetting() {
179
                    return false;
180
                }
181

    
182
                @Override
183
                public String[] getRequiredFieldNames() {
184
                    return new String[] { xFieldName, yFieldName };
185
                }
186

    
187
                @Override
188
                public JsonObject toJson() {
189
                    return null;
190
                }
191

    
192
                @Override
193
                public JsonObjectBuilder toJsonBuilder() {
194
                    return null;
195
                }
196

    
197
                @Override
198
                public void fromJson(JsonObject json) {
199
                }
200
            });
201
        }
202

    
203
        try {
204
            /*
205
             * creates and updates envelope with all features
206
             */
207
            initEnvelope(this.getFeatureStore(), MAX_INI_FEATURES);
208
        } catch (CreateEnvelopeException e) {
209
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
210
        }
211

    
212
        type.setDefaultGeometryAttributeName(this.geometryFieldName);
213
        FeatureType[] types = new FeatureType[]{type.getNotEditableCopy()};
214
        setFeatureTypes(Arrays.asList(types), types[0]);
215
    }
216

    
217
    /**
218
     * creates and updates envelope with all features
219
     *
220
     */
221
    private void initEnvelope(FeatureStore theStore, int max_feats) throws CreateEnvelopeException {
222

    
223
        envelope = geometryManager.createEnvelope(SUBTYPES.GEOM2D);
224
        FeatureSet fset = null;
225
        DisposableIterator diter = null;
226
        Feature feat = null;
227
        try {
228
            fset = theStore.getFeatureSet();
229
            diter = fset.fastIterator();
230

    
231
            // int count = 0;
232
            int countused = 0;
233
            int nextwait = 1;
234
            int index = 0;
235

    
236
            while( diter.hasNext() && (countused < max_feats) ) {
237

    
238
                feat = (Feature) diter.next();
239
                /*
240
                 * This loop will use about 70 features from the first
241
                 * 3000 features, more and more separated each time.
242
                 * Something like:
243
                 * 
244
                 * 1st, 2nd ,3rd, 5th, 8th, 15, 25, 40, 100, 300...
245
                 * 
246
                 * Other features are ignored with diter.next().
247
                 * That causes an acceptable behavior even if the store
248
                 * is very large.
249
                 * 
250
                 * Afterwards, the extent is updated while drawing,
251
                 * so it's not very important.
252
                 */
253
                index++;
254
                if( index == nextwait ) {
255
                    index = 0;
256
                    /*
257
                         * This causes that the first 5 features
258
                         * will always be used.
259
                     */
260
                    if( countused > 5 ) {
261
                        nextwait++;
262
                    }
263
                    this.updateEnvelope(feat);
264
                    countused++;
265
                }
266
                // count++;
267
            }
268

    
269
            diter.dispose();
270

    
271
        } catch (Exception dex) {
272
            throw new CreateEnvelopeException(SUBTYPES.GEOM2D, dex);
273
        }
274
    }
275

    
276
    public void setEnvelope(Envelope env) {
277
        this.envelope = env;
278
    }
279

    
280
    @Override
281
    public void applyTransform(Feature source, EditableFeature target)
282
        throws DataException {        
283
        target.copyFrom(source);
284
    }
285

    
286
    /**
287
     * Used internally to initialize envelope
288
     *
289
     */
290
    private void updateEnvelope(Feature feat) throws CreateGeometryException {
291

    
292
        Point point = geometryManager.createPoint(
293
            new Double(feat.get(xFieldName).toString()),
294
            new Double(feat.get(yFieldName).toString()),
295
            SUBTYPES.GEOM2D);
296
        envelope.add(point.getEnvelope());
297
    }
298

    
299
    @Override
300
    public FeatureType getSourceFeatureTypeFrom(FeatureType targetFeatureType) {
301
        return this.originalFeatureType;
302
    }
303

    
304
    @Override
305
    public boolean isTransformsOriginalValues() {
306
        return true;
307
    }
308

    
309
    public static void registerPersistent() {
310
        PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
311

    
312
        if( persistenceManager.getDefinition(AbstractFeatureStoreTransform.class) == null ) {
313
            AbstractFeatureStoreTransform.registerPersistent();
314
        }
315

    
316
        DynStruct definition = persistenceManager.getDefinition(PERSISTENCE_DEFINITION_NAME);
317

    
318
        if( definition == null ) {
319
            definition = persistenceManager.addDefinition(
320
                EventThemeTransform.class,
321
                PERSISTENCE_DEFINITION_NAME,
322
                "EventThemeTransform Persistence definition",
323
                null,
324
                null
325
            );
326
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
327
                ABSTRACT_FEATURESTORE_DYNCLASS_NAME);
328

    
329
            definition.addDynFieldString("geometryFieldName").setMandatory(true);
330
            definition.addDynFieldString("xFieldName").setMandatory(true);
331
            definition.addDynFieldString("yFieldName").setMandatory(true);
332
            definition.addDynFieldObject("projection").setType(DataTypes.CRS);
333
        }
334
    }
335

    
336
    @Override
337
    public void saveToState(PersistentState state) throws PersistenceException {
338
        super.saveToState(state);
339
        state.set("geometryFieldName", this.geometryFieldName);
340
        state.set("xFieldName", this.xFieldName);
341
        state.set("yFieldName", this.yFieldName);
342
        state.set("projection", this.projection);
343
    }
344

    
345
    @Override
346
    public void loadFromState(PersistentState state)
347
        throws PersistenceException {
348
        super.loadFromState(state);
349
        geometryFieldName = state.getString("geometryFieldName");
350
        xFieldName = state.getString("xFieldName");
351
        yFieldName = state.getString("yFieldName");
352
        projection = (IProjection) state.get("projection");
353
    }
354

    
355
    @Override
356
    public Object getDynValue(String name) throws DynFieldNotFoundException {
357
        if( DataStore.METADATA_CRS.equals(name) ) {
358
            return projection;
359
        } else if( DataStore.METADATA_ENVELOPE.equals(name) ) {
360
            return envelope;
361
        }
362
        return null;
363
    }
364

    
365
    @Override
366
    public boolean hasDynValue(String name) {
367
        return ((DataStore.METADATA_CRS.equals(name))
368
            || (DataStore.METADATA_ENVELOPE.equals(name)));
369
    }
370

    
371
}