svn-gvsig-desktop / branches / org.gvsig.desktop-cvsgis1 / 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 @ 45267
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 |
} |