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