Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontal/HorizontalProfileMeshCrossOutputState.java @ 420:c6a287398379
Outsourcing of some methods for preparing results for chart creation.
gnv-artifacts/trunk@468 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Mon, 21 Dec 2009 15:57:04 +0000 |
parents | 6eae1efb5fc3 |
children | 2402173a1490 |
comparison
equal
deleted
inserted
replaced
419:1e192ea34e80 | 420:c6a287398379 |
---|---|
1 /** | 1 /** |
2 * | 2 * |
3 */ | 3 */ |
4 package de.intevation.gnv.state.profile.horizontal; | 4 package de.intevation.gnv.state.profile.horizontal; |
5 | 5 |
6 import java.util.ArrayList; | |
7 import java.util.Arrays; | |
8 import java.util.Collection; | 6 import java.util.Collection; |
9 import java.util.List; | |
10 import java.util.Locale; | 7 import java.util.Locale; |
11 | 8 |
12 import org.apache.log4j.Logger; | 9 import org.apache.log4j.Logger; |
13 import org.w3c.dom.Node; | 10 import org.w3c.dom.Node; |
14 | 11 |
15 import com.vividsolutions.jts.geom.Coordinate; | |
16 import com.vividsolutions.jts.geom.Point; | |
17 import com.vividsolutions.jts.geom.LineString; | |
18 | |
19 import com.vividsolutions.jts.io.ParseException; | 12 import com.vividsolutions.jts.io.ParseException; |
20 import com.vividsolutions.jts.io.WKTReader; | |
21 | 13 |
22 import de.intevation.artifactdatabase.Config; | 14 import de.intevation.artifactdatabase.Config; |
23 | 15 |
24 import de.intevation.gnv.artifacts.cache.CacheFactory; | 16 import de.intevation.gnv.artifacts.cache.CacheFactory; |
25 | 17 |
26 import de.intevation.gnv.chart.Chart; | 18 import de.intevation.gnv.chart.Chart; |
27 import de.intevation.gnv.chart.ChartLabels; | 19 import de.intevation.gnv.chart.ChartLabels; |
28 import de.intevation.gnv.chart.HorizontalCrossProfileChart; | 20 import de.intevation.gnv.chart.HorizontalCrossProfileChart; |
29 | 21 |
30 import de.intevation.gnv.geobackend.base.DefaultResultDescriptor; | |
31 import de.intevation.gnv.geobackend.base.ResultDescriptor; | |
32 import de.intevation.gnv.geobackend.base.DefaultResult; | |
33 import de.intevation.gnv.geobackend.base.Result; | 22 import de.intevation.gnv.geobackend.base.Result; |
34 | 23 |
35 import de.intevation.gnv.math.Point2d; | 24 import de.intevation.gnv.geobackend.base.query.exception.QueryException; |
36 import de.intevation.gnv.math.Interpolation2D; | |
37 | 25 |
38 import de.intevation.gnv.geobackend.base.query.QueryExecutor; | 26 import de.intevation.gnv.utils.WKTUtils; |
39 import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; | |
40 import de.intevation.gnv.geobackend.base.query.exception.QueryException; | |
41 import de.intevation.gnv.geobackend.sde.datasources.ResultSet; | |
42 | |
43 | |
44 import de.intevation.gnv.utils.IndexBuffer; | |
45 import de.intevation.gnv.utils.DistanceCalculator; | |
46 | |
47 import de.intevation.gnv.math.LinearFunction; | |
48 import de.intevation.gnv.math.LinearMetrics; | |
49 | |
50 import org.apache.commons.math.optimization.fitting.CurveFitter; | |
51 | |
52 import org.apache.commons.math.optimization.general.GaussNewtonOptimizer; | |
53 import org.apache.commons.math.optimization.OptimizationException; | |
54 | |
55 import org.apache.commons.math.FunctionEvaluationException; | |
56 | 27 |
57 import org.jfree.chart.ChartTheme; | 28 import org.jfree.chart.ChartTheme; |
58 | 29 |
59 /** | 30 /** |
60 * @author Tim Englich <tim.englich@intevation.de> | 31 * @author Tim Englich <tim.englich@intevation.de> |
153 }else{ | 124 }else{ |
154 | 125 |
155 if (this.inputData.containsKey("mesh_linestring")){ | 126 if (this.inputData.containsKey("mesh_linestring")){ |
156 | 127 |
157 try { | 128 try { |
158 // 1. IJK Anfragen für Stuetzpunkte im Netz ausführen. | 129 result = WKTUtils.worldCoordinatesToIndex( |
159 LineString ls = (LineString)new WKTReader().read(this.inputData | 130 result, |
160 .get("mesh_linestring") | 131 inputData, |
161 .getValue()); | 132 ijkQueryID, |
162 Coordinate[] coords = ls.getCoordinates(); | 133 queryID, |
163 | 134 generateFilterValuesFromInputData() |
164 List<java.awt.Point> points = new ArrayList<java.awt.Point>(coords.length); | 135 ); |
165 | |
166 String meshid = this.inputData.get("meshid").getValue(); | |
167 QueryExecutor queryExecutor = QueryExecutorFactory | |
168 .getInstance() | |
169 .getQueryExecutor(); | |
170 | |
171 ArrayList missingPoints = new ArrayList(); | |
172 | |
173 String additionWhere = "FEATUREID=FEATUREID"; | |
174 | |
175 for (int i = 0; i < coords.length; i++) { | |
176 | |
177 String wkt = toWKT(coords[i]); | |
178 | |
179 result = queryExecutor.executeQuery(this.ijkQueryID, | |
180 new String[]{meshid,wkt}); | |
181 if (!result.isEmpty()){ | |
182 Result resultValue = result.iterator().next(); | |
183 int iPos = resultValue.getInteger(1); | |
184 int jPos = resultValue.getInteger(0); | |
185 log.debug("Found Pos "+iPos+"/"+jPos +" for "+wkt); | |
186 points.add(i, new java.awt.Point(iPos,jPos)); | |
187 }else{ | |
188 log.debug("No i/j Pos found for "+wkt); | |
189 missingPoints.add(new Object [] { Integer.valueOf(i), coords[i] }); | |
190 points.add(i, null); | |
191 // Special Case no i,j found for Coordinate | |
192 } | |
193 } | |
194 | |
195 if (missingPoints.size() == coords.length) { | |
196 log.debug("cannot create index buffer"); | |
197 } | |
198 else { // generate index filter | |
199 boolean remainsMissingPoints = !missingPoints.isEmpty(); | |
200 | |
201 if (remainsMissingPoints) { | |
202 // try to guess the missing (i, j) | |
203 CurveFitter iFitter = new CurveFitter(new GaussNewtonOptimizer(true)); | |
204 CurveFitter jFitter = new CurveFitter(new GaussNewtonOptimizer(true)); | |
205 | |
206 for (int i = 0, N = points.size(); i < N; ++i) { | |
207 java.awt.Point p = (java.awt.Point)points.get(i); | |
208 if (p != null) { | |
209 Coordinate coord = coords[i]; | |
210 iFitter.addObservedPoint(coord.x, p.x); | |
211 jFitter.addObservedPoint(coord.y, p.y); | |
212 } | |
213 } | |
214 try { | |
215 // XXX: Assumption: (i, j) are created by componentwise linear function. | |
216 // This is surely not correct because (x, y) are in a ellipsoid projection. | |
217 // TODO: use ellipsoid functions and fit with Levenberg Marquardt. | |
218 double [] iParams = iFitter.fit( | |
219 LinearFunction.INSTANCE, new double [] { 1d, 1d }); | |
220 | |
221 double [] jParams = jFitter.fit( | |
222 LinearFunction.INSTANCE, new double [] { 1d, 1d }); | |
223 | |
224 for (int i = missingPoints.size()-1; i >= 0; --i) { | |
225 Object [] a = (Object [])missingPoints.get(i); | |
226 Coordinate coord = (Coordinate)a[1]; | |
227 int pi = (int)Math.round(iParams[0]*coord.x + iParams[1]); | |
228 int pj = (int)Math.round(jParams[0]*coord.y + jParams[1]); | |
229 points.set( | |
230 ((Integer)a[0]).intValue(), | |
231 new java.awt.Point(pi, pj)); | |
232 } | |
233 | |
234 remainsMissingPoints = false; // we filled the gaps | |
235 } | |
236 catch (FunctionEvaluationException fee) { | |
237 log.error(fee); | |
238 } | |
239 catch (OptimizationException oe) { | |
240 log.error(oe); | |
241 } | |
242 } | |
243 | |
244 if (!remainsMissingPoints) { | |
245 // TODO: Make Tablenames and Columns Configurable | |
246 IndexBuffer ib = new IndexBuffer( | |
247 points, | |
248 "MEDIAN.MESHPOINT.IPOSITION", | |
249 "MEDIAN.MESHPOINT.JPOSITION" ); | |
250 additionWhere = ib.toWhereClause(); | |
251 log.debug("Additional Where Clause = "+additionWhere); | |
252 // 2. Aus diesen Stuetzpunkten den Resultset generieren. | |
253 } | |
254 } // if generate index filter | |
255 | |
256 String[] filterValues = this.generateFilterValuesFromInputData(); | |
257 String[] addedFilterValues = new String[filterValues.length+1]; | |
258 System.arraycopy(filterValues, 0, addedFilterValues, 0, filterValues.length); | |
259 addedFilterValues[filterValues.length] = additionWhere; | |
260 | |
261 result = process( | |
262 Arrays.asList(coords), | |
263 queryExecutor.executeQuery( | |
264 this.queryID, | |
265 addedFilterValues)); | |
266 | |
267 } catch (ParseException e) { | 136 } catch (ParseException e) { |
268 log.error(e,e); | 137 log.error(e,e); |
269 }catch (QueryException e) { | 138 }catch (QueryException e) { |
270 log.error(e,e); | 139 log.error(e,e); |
271 } | 140 } |
288 log.debug("create chart subtitle for horizontal crossprofile charts."); | 157 log.debug("create chart subtitle for horizontal crossprofile charts."); |
289 String subtitle = createTimePeriod(locale, uuid); | 158 String subtitle = createTimePeriod(locale, uuid); |
290 | 159 |
291 return subtitle; | 160 return subtitle; |
292 } | 161 } |
293 | |
294 private static final String [] COLUMN_BLACKLIST = { | |
295 "MEDIAN.MESHPOINT.JPOSITION", | |
296 "MEDIAN.MESHPOINT.IPOSITION" | |
297 }; | |
298 | |
299 private static final boolean blacklisted(String column) { | |
300 for (int i = 0; i < COLUMN_BLACKLIST.length; ++i) { | |
301 if (COLUMN_BLACKLIST.equals(column)) { | |
302 return true; | |
303 } | |
304 } | |
305 return false; | |
306 } | |
307 | |
308 private static boolean different(Result a, Result b, int [] indices) { | |
309 for (int i = 0; i < indices.length; ++i) { | |
310 String oa = a.getString(indices[i]); | |
311 String ob = b.getString(indices[i]); | |
312 | |
313 if (oa == null && ob == null) { | |
314 continue; | |
315 } | |
316 | |
317 if (oa == null || ob == null) { | |
318 return true; | |
319 } | |
320 | |
321 if (!oa.equals(ob)) { | |
322 if (log.isDebugEnabled()) { | |
323 log.debug("+++++++++++++++ differs ++++++++++++++"); | |
324 log.debug(" " + oa + " != " + ob); | |
325 } | |
326 return true; | |
327 } | |
328 } | |
329 return false; | |
330 } | |
331 | |
332 private static final String [] DIFF_COLUMS = { | |
333 "GROUP1", | |
334 "GROUP2", | |
335 "GROUP3" | |
336 }; | |
337 | |
338 public static final class SectionHandler | |
339 implements Interpolation2D.Consumer | |
340 { | |
341 private ArrayList<Point2d> points; | |
342 private List<Coordinate> path; | |
343 private Collection<Result> output; | |
344 private Result prototyp; | |
345 private ResultDescriptor descriptor; | |
346 private boolean lastWasSuccess; | |
347 | |
348 public SectionHandler() { | |
349 } | |
350 | |
351 public SectionHandler( | |
352 List<Coordinate> path, | |
353 Collection<Result> output, | |
354 ResultDescriptor descriptor | |
355 ) { | |
356 this.path = path; | |
357 this.output = output; | |
358 this.descriptor = descriptor; | |
359 points = new ArrayList<Point2d>(); | |
360 lastWasSuccess = true; | |
361 } | |
362 | |
363 public void finish() { | |
364 if (!points.isEmpty()) { | |
365 double distance = toKM( | |
366 DistanceCalculator.calculateDistance(path)); | |
367 | |
368 if (distance > EPSILON) { | |
369 | |
370 Interpolation2D.interpolate( | |
371 path, | |
372 points, | |
373 0d, | |
374 distance, | |
375 INTERPOLATION_STEPS, | |
376 LinearMetrics.INSTANCE, | |
377 this); | |
378 } | |
379 | |
380 points.clear(); | |
381 } | |
382 lastWasSuccess = true; | |
383 } | |
384 | |
385 public void setPrototyp(Result prototyp) { | |
386 this.prototyp = prototyp; | |
387 } | |
388 | |
389 public void handle(Result result) { | |
390 Coordinate coordinate = | |
391 toCoordinate(result.getString("SHAPE")); | |
392 double value = result.getDouble("YORDINATE"); | |
393 int iPos = result.getInteger("MEDIAN.MESHPOINT.JPOSITION"); | |
394 int jPos = result.getInteger("MEDIAN.MESHPOINT.JPOSITION"); | |
395 Point2d p = new Point2d( | |
396 coordinate.x, | |
397 coordinate.y, | |
398 value, | |
399 iPos, jPos); | |
400 points.add(p); | |
401 } | |
402 | |
403 public void interpolated(Coordinate coordinate, boolean success) { | |
404 DefaultResult result = new DefaultResult(descriptor); | |
405 ResultDescriptor pd = prototyp.getResultDescriptor(); | |
406 | |
407 int pcolums = pd.getColumnCount(); | |
408 for (int i = 0, j = 0; i < pcolums; ++i) { | |
409 String colname = pd.getColumnName(i); | |
410 if (blacklisted(colname)) { | |
411 continue; | |
412 } | |
413 if (colname.equals("SHAPE")) { | |
414 result.addColumnValue(j, toWKT(coordinate)); | |
415 } | |
416 else if (colname.equals("YORDINATE")) { | |
417 if (success) { | |
418 result.addColumnValue(j, Double.valueOf(coordinate.z)); | |
419 } | |
420 else if (lastWasSuccess) { | |
421 // only insert null if last was valid. | |
422 // This prevents flooding the result set with nulls | |
423 // if interpolating over a large gap. | |
424 result.addColumnValue(j, null); | |
425 } | |
426 } | |
427 else { | |
428 result.addColumnValue(j, prototyp.getObject(i)); | |
429 } | |
430 ++j; | |
431 } | |
432 output.add(result); | |
433 lastWasSuccess = success; | |
434 } | |
435 } // class SectionHandler | |
436 | |
437 public static final double NAUTICAL_MILE = 1852.216d; | |
438 public static final double KILOMETER = 1000d; | |
439 | |
440 public static final double toKM(double distance) { | |
441 return (distance * NAUTICAL_MILE) / KILOMETER; | |
442 } | |
443 | |
444 public static final double EPSILON = 1e-5d; | |
445 public static final int INTERPOLATION_STEPS = | |
446 Integer.getInteger("interpolation.steps", 500).intValue(); | |
447 | |
448 public static Coordinate toCoordinate(String shape) { | |
449 try { | |
450 return ((Point)(new WKTReader().read(shape))).getCoordinate(); | |
451 } | |
452 catch (ParseException pe) { | |
453 log.error(pe); | |
454 } | |
455 return null; | |
456 } | |
457 | |
458 public static String toWKT(Coordinate coordinate) { | |
459 StringBuilder sb = new StringBuilder("POINT("); | |
460 sb.append(coordinate.x) | |
461 .append(' ') | |
462 .append(coordinate.y) | |
463 .append(')'); | |
464 return sb.toString(); | |
465 } | |
466 | |
467 protected Collection<Result> process( | |
468 List<Coordinate> path, | |
469 Collection<Result> input | |
470 ) { | |
471 log.debug("------ number of points before processing: " + input.size()); | |
472 ArrayList<Result> output = new ArrayList<Result>(); | |
473 | |
474 | |
475 Result last = null; | |
476 | |
477 int [] diffColums = null; | |
478 | |
479 SectionHandler sectionHandler = null; | |
480 | |
481 for (Result result: input) { | |
482 | |
483 if (sectionHandler == null) { | |
484 | |
485 ResultDescriptor rd = result.getResultDescriptor(); | |
486 diffColums = rd.getColumnIndices(DIFF_COLUMS); | |
487 int columns = rd.getColumnCount(); | |
488 | |
489 DefaultResultDescriptor resultDescriptor = | |
490 new DefaultResultDescriptor(); | |
491 | |
492 for (int j = 0; j < columns; ++j) { | |
493 String columnName = rd.getColumnName(j); | |
494 if (!blacklisted(columnName)) { | |
495 resultDescriptor.addColumn( | |
496 columnName, | |
497 rd.getColumnClassName(j)); | |
498 } | |
499 } | |
500 | |
501 sectionHandler = new SectionHandler( | |
502 path, | |
503 output, | |
504 resultDescriptor); | |
505 | |
506 sectionHandler.setPrototyp(result); | |
507 } | |
508 | |
509 if (last != null && different(last, result, diffColums)) { | |
510 sectionHandler.finish(); | |
511 sectionHandler.setPrototyp(result); | |
512 } | |
513 | |
514 sectionHandler.handle(result); | |
515 | |
516 last = result; | |
517 } | |
518 | |
519 if (sectionHandler != null) { | |
520 sectionHandler.finish(); | |
521 } | |
522 | |
523 log.debug("------ number of points after processing: " + output.size()); | |
524 | |
525 return output; | |
526 } | |
527 } | 162 } |