Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java @ 2562:ba35dfb7c09a
FixingsOverview: Construct the Q sectors once.
flys-artifacts/trunk@4088 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 20 Feb 2012 14:36:28 +0000 |
parents | b3f6d49cdc80 |
children | 59c920e73d8a |
comparison
equal
deleted
inserted
replaced
2561:b3f6d49cdc80 | 2562:ba35dfb7c09a |
---|---|
117 "SELECT" + | 117 "SELECT" + |
118 " MIN(position) AS start_km," + | 118 " MIN(position) AS start_km," + |
119 " MAX(position) AS stop_km " + | 119 " MAX(position) AS stop_km " + |
120 "FROM" + | 120 "FROM" + |
121 " wst_column_values " + | 121 " wst_column_values " + |
122 "WHERE " + | 122 "WHERE" + |
123 " wst_column_id = :column_id"; | 123 " wst_column_id = :column_id"; |
124 | 124 |
125 public static class Range implements Serializable { | 125 public static class Range implements Serializable { |
126 | 126 |
127 protected double start; | 127 protected double start; |
133 public Range(double start, double end) { | 133 public Range(double start, double end) { |
134 this.start = start; | 134 this.start = start; |
135 this.end = end; | 135 this.end = end; |
136 } | 136 } |
137 | 137 |
138 public double getStart() { | |
139 return start; | |
140 } | |
141 | |
142 public double getEnd() { | |
143 return end; | |
144 } | |
145 | |
138 public boolean disjoint(Range other) { | 146 public boolean disjoint(Range other) { |
139 return start > other.end || other.start > end; | 147 return start > other.end || other.start > end; |
148 } | |
149 | |
150 public boolean intersects(Range other) { | |
151 return !disjoint(other); | |
140 } | 152 } |
141 | 153 |
142 public boolean clip(Range other) { | 154 public boolean clip(Range other) { |
143 if (disjoint(other)) return false; | 155 if (disjoint(other)) return false; |
144 | 156 |
227 } | 239 } |
228 return sectors.size(); | 240 return sectors.size(); |
229 } | 241 } |
230 } // class GaugeRange | 242 } // class GaugeRange |
231 | 243 |
244 public static class GaugeFinder { | |
245 | |
246 protected List<GaugeRange> gauges; | |
247 protected boolean isKmUp; | |
248 | |
249 public GaugeFinder(List<GaugeRange> gauges) { | |
250 this(gauges, true); | |
251 } | |
252 | |
253 public GaugeFinder( | |
254 List<GaugeRange> gauges, | |
255 boolean isKmUp | |
256 ) { | |
257 this.gauges = gauges; | |
258 this.isKmUp = isKmUp; | |
259 } | |
260 | |
261 public boolean getIsKmUp() { | |
262 return isKmUp; | |
263 } | |
264 | |
265 public void setIsKmUp(boolean isKmUp) { | |
266 this.isKmUp = isKmUp; | |
267 } | |
268 | |
269 public GaugeRange find(Range range) { | |
270 double km = isKmUp ? range.start : range.end; | |
271 for (GaugeRange gauge: gauges) { | |
272 if (gauge.inside(km)) { | |
273 return gauge; | |
274 } | |
275 } | |
276 return null; | |
277 } | |
278 | |
279 public GaugeRange find(int gaugeId) { | |
280 for (GaugeRange gauge: gauges) { | |
281 if (gauge.gaugeId == gaugeId) { | |
282 return gauge; | |
283 } | |
284 } | |
285 return null; | |
286 } | |
287 | |
288 public boolean loadDischargeSectors(Session session, int riverId) { | |
289 | |
290 SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS) | |
291 .addScalar("gauge_id", StandardBasicTypes.INTEGER) | |
292 .addScalar("name", StandardBasicTypes.STRING) | |
293 .addScalar("value", StandardBasicTypes.DOUBLE); | |
294 | |
295 query.setInteger("river_id", riverId); | |
296 | |
297 List<Object []> list = query.list(); | |
298 | |
299 if (list.isEmpty()) { | |
300 log.warn("River " + riverId + " has no discharge sectors."); | |
301 return false; | |
302 } | |
303 | |
304 GaugeRange gauge = null; | |
305 | |
306 for (Object [] row: list) { | |
307 int gaugeId = (Integer)row[0]; | |
308 String label = (String) row[1]; | |
309 Double value = (Double) row[2]; | |
310 | |
311 if (gauge == null || gauge.gaugeId != gaugeId) { | |
312 if ((gauge = find(gaugeId)) == null) { | |
313 log.warn("Cannot find gauge for id " + gaugeId + "."); | |
314 continue; | |
315 } | |
316 } | |
317 | |
318 gauge.addMainValue(label, value); | |
319 } | |
320 | |
321 for (GaugeRange g: gauges) { | |
322 g.buildClasses(); | |
323 } | |
324 | |
325 return true; | |
326 } | |
327 } // class GaugeFinder | |
328 | |
232 public static class QRange extends Range { | 329 public static class QRange extends Range { |
233 | 330 |
234 protected double q; | 331 protected double q; |
235 | 332 |
236 public QRange() { | 333 public QRange() { |
247 protected int sector; | 344 protected int sector; |
248 | 345 |
249 public SectorRange() { | 346 public SectorRange() { |
250 } | 347 } |
251 | 348 |
349 public SectorRange(SectorRange other) { | |
350 start = other.start; | |
351 end = other.end; | |
352 sector = other.sector; | |
353 } | |
354 | |
252 public SectorRange(double start, double end, int sector) { | 355 public SectorRange(double start, double end, int sector) { |
253 super(start, end); | 356 super(start, end); |
254 this.sector = sector; | 357 this.sector = sector; |
358 } | |
359 | |
360 public int getSector() { | |
361 return sector; | |
255 } | 362 } |
256 | 363 |
257 public boolean enlarge(SectorRange other) { | 364 public boolean enlarge(SectorRange other) { |
258 if (sector == other.sector | 365 if (sector == other.sector |
259 && Math.abs(end-other.start) < EPSILON2) { | 366 && Math.abs(end-other.start) < EPSILON2) { |
278 | 385 |
279 protected int columnId; | 386 protected int columnId; |
280 protected Date startTime; | 387 protected Date startTime; |
281 protected String name; | 388 protected String name; |
282 | 389 |
283 protected List<QRange> qRanges; | 390 protected List<SectorRange> sectors; |
284 | 391 |
285 public Column() { | 392 public Column() { |
286 } | 393 } |
287 | 394 |
288 public Column(int columnId, Date startTime, String name) { | 395 public Column(int columnId, Date startTime, String name) { |
289 this.columnId = columnId; | 396 this.columnId = columnId; |
290 this.startTime = startTime; | 397 this.startTime = startTime; |
291 this.name = name; | 398 this.name = name; |
292 | 399 |
293 qRanges = new ArrayList<QRange>(); | 400 sectors = new ArrayList<SectorRange>(); |
294 } | 401 } |
295 | 402 |
296 public Fixing getFixing() { | 403 public Fixing getFixing() { |
297 return Fixing.this; | 404 return Fixing.this; |
298 } | 405 } |
299 | 406 |
300 public List<SectorRange> classify(GaugeRange gauge) { | 407 public List<SectorRange> getSectors() { |
301 | 408 return sectors; |
302 List<SectorRange> sectors = new ArrayList<SectorRange>(); | 409 } |
410 | |
411 public void buildSectors(GaugeRange gauge, List<QRange> qRanges) { | |
303 | 412 |
304 for (QRange qRange: qRanges) { | 413 for (QRange qRange: qRanges) { |
305 SectorRange sector = new SectorRange( | 414 SectorRange sector = new SectorRange( |
306 qRange.start, qRange.end, | 415 qRange.start, qRange.end, |
307 gauge.classify(qRange.q)); | 416 gauge.classify(qRange.q)); |
308 if (sectors.isEmpty() | 417 if (sectors.isEmpty() |
309 || !sectors.get(sectors.size()-1).enlarge(sector)) { | 418 || !sectors.get(sectors.size()-1).enlarge(sector)) { |
310 sectors.add(sector); | 419 sectors.add(sector); |
311 } | 420 } |
312 } | 421 } |
313 | |
314 return sectors; | |
315 } | 422 } |
316 | 423 |
317 public void loadKmRange(SQLQuery query) { | 424 public void loadKmRange(SQLQuery query) { |
318 query.setInteger("column_id", columnId); | 425 query.setInteger("column_id", columnId); |
319 | 426 |
327 start = (Double)obj[0]; | 434 start = (Double)obj[0]; |
328 end = (Double)obj[1]; | 435 end = (Double)obj[1]; |
329 } | 436 } |
330 } | 437 } |
331 | 438 |
332 public void loadQRanges(SQLQuery query) { | 439 public void loadQRanges( |
440 SQLQuery query, | |
441 GaugeFinder gaugeFinder | |
442 ) { | |
333 query.setInteger("column_id", columnId); | 443 query.setInteger("column_id", columnId); |
334 List<Object []> list = query.list(); | 444 List<Object []> list = query.list(); |
445 | |
446 List<QRange> qRanges = new ArrayList<QRange>(list.size()); | |
335 | 447 |
336 for (Object [] row: list) { | 448 for (Object [] row: list) { |
337 double q = (Double)row[0]; | 449 double q = (Double)row[0]; |
338 double start = (Double)row[1]; | 450 double start = (Double)row[1]; |
339 double end = (Double)row[2]; | 451 double end = (Double)row[2]; |
340 QRange qRange = new QRange(start, end, q); | 452 QRange qRange = new QRange(start, end, q); |
341 if (qRange.clip(this)) { | 453 if (qRange.clip(this)) { |
342 qRanges.add(qRange); | 454 qRanges.add(qRange); |
343 } | 455 } |
344 } | 456 } |
457 | |
458 GaugeRange gauge = gaugeFinder.find(this); | |
459 | |
460 if (gauge != null) { | |
461 buildSectors(gauge, qRanges); | |
462 } | |
463 else { | |
464 log.warn("No gauge found for column " + columnId + "."); | |
465 } | |
345 } | 466 } |
346 } // class Column | 467 } // class Column |
347 | 468 |
348 protected int wstId; | 469 protected int wstId; |
349 protected String description; | 470 protected String description; |
350 protected List<Column> columns; | 471 protected List<Column> columns; |
351 | 472 |
352 public Fixing() { | 473 public Fixing() { |
353 } | 474 } |
354 | 475 |
373 for (Column column: columns) { | 494 for (Column column: columns) { |
374 column.loadKmRange(query); | 495 column.loadKmRange(query); |
375 } | 496 } |
376 } | 497 } |
377 | 498 |
378 public void loadColumnsQRanges(SQLQuery query) { | 499 public void loadColumnsQRanges( |
500 SQLQuery query, | |
501 GaugeFinder gaugeFinder | |
502 ) { | |
379 for (Column column: columns) { | 503 for (Column column: columns) { |
380 column.loadQRanges(query); | 504 column.loadQRanges(query, gaugeFinder); |
381 } | 505 } |
382 } | 506 } |
383 | 507 |
384 public void addAllColumns(List<Column> allColumns) { | 508 public void addAllColumns(List<Column> allColumns, Range range) { |
385 allColumns.addAll(columns); | 509 for (Column column: columns) { |
510 if (column.intersects(range)) { | |
511 allColumns.add(column); | |
512 } | |
513 } | |
386 } | 514 } |
387 } // class Fixing | 515 } // class Fixing |
388 | 516 |
389 | 517 |
390 protected String riverName; | 518 protected String riverName; |
391 protected int riverId; | 519 protected int riverId; |
392 protected boolean isKmUp; | 520 protected boolean isKmUp; |
393 protected List<GaugeRange> gauges; | 521 protected List<Fixing> fixings; |
394 protected List<Fixing> fixings; | 522 protected Range extent; |
395 protected Range extent; | |
396 | 523 |
397 public FixingsOverview() { | 524 public FixingsOverview() { |
398 gauges = new ArrayList<GaugeRange>(); | |
399 fixings = new ArrayList<Fixing>(); | 525 fixings = new ArrayList<Fixing>(); |
400 } | 526 } |
401 | 527 |
402 public FixingsOverview(String riverName) { | 528 public FixingsOverview(String riverName) { |
403 this(); | 529 this(); |
444 extent = new Range((Double)row[0], (Double)row[1]); | 570 extent = new Range((Double)row[0], (Double)row[1]); |
445 | 571 |
446 return true; | 572 return true; |
447 } | 573 } |
448 | 574 |
449 | 575 protected GaugeFinder loadGauges(Session session) { |
450 protected boolean loadGauges(Session session) { | |
451 SQLQuery query = session.createSQLQuery(SQL_GAUGES) | 576 SQLQuery query = session.createSQLQuery(SQL_GAUGES) |
452 .addScalar("gauge_id", StandardBasicTypes.INTEGER) | 577 .addScalar("gauge_id", StandardBasicTypes.INTEGER) |
453 .addScalar("a", StandardBasicTypes.DOUBLE) | 578 .addScalar("a", StandardBasicTypes.DOUBLE) |
454 .addScalar("b", StandardBasicTypes.DOUBLE); | 579 .addScalar("b", StandardBasicTypes.DOUBLE); |
455 | 580 |
457 | 582 |
458 List<Object []> list = query.list(); | 583 List<Object []> list = query.list(); |
459 | 584 |
460 if (list.isEmpty()) { | 585 if (list.isEmpty()) { |
461 log.warn("River " + riverId + " has no gauges."); | 586 log.warn("River " + riverId + " has no gauges."); |
462 return false; | 587 return null; |
463 } | 588 } |
589 | |
590 List<GaugeRange> gauges = new ArrayList<GaugeRange>(); | |
464 | 591 |
465 for (Object [] row: list) { | 592 for (Object [] row: list) { |
466 int gaugeId = (Integer)row[0]; | 593 int gaugeId = (Integer)row[0]; |
467 double start = (Double) row[1]; | 594 double start = (Double) row[1]; |
468 double end = (Double) row[2]; | 595 double end = (Double) row[2]; |
469 GaugeRange gauge = new GaugeRange(start, end, gaugeId); | 596 GaugeRange gauge = new GaugeRange(start, end, gaugeId); |
470 gauges.add(gauge); | 597 gauges.add(gauge); |
471 } | 598 } |
472 | 599 |
473 return true; | 600 return new GaugeFinder(gauges, isKmUp); |
474 } | 601 } |
475 | 602 |
476 protected GaugeRange findGaugeById(int gaugeId) { | |
477 for (GaugeRange gauge: gauges) { | |
478 if (gauge.gaugeId == gaugeId) { | |
479 return gauge; | |
480 } | |
481 } | |
482 return null; | |
483 } | |
484 | |
485 protected GaugeRange findGaugeByKm(double km) { | |
486 for (GaugeRange gauge: gauges) { | |
487 if (gauge.inside(km)) { | |
488 return gauge; | |
489 } | |
490 } | |
491 return null; | |
492 } | |
493 | |
494 protected boolean loadDischargeSectors(Session session) { | |
495 | |
496 SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS) | |
497 .addScalar("gauge_id", StandardBasicTypes.INTEGER) | |
498 .addScalar("name", StandardBasicTypes.STRING) | |
499 .addScalar("value", StandardBasicTypes.DOUBLE); | |
500 | |
501 query.setInteger("river_id", riverId); | |
502 | |
503 List<Object []> list = query.list(); | |
504 | |
505 if (list.isEmpty()) { | |
506 log.warn("River " + riverId + " has no discharge sectors."); | |
507 return false; | |
508 } | |
509 | |
510 GaugeRange gauge = null; | |
511 | |
512 for (Object [] row: list) { | |
513 int gaugeId = (Integer)row[0]; | |
514 String label = (String) row[1]; | |
515 Double value = (Double) row[2]; | |
516 | |
517 if (gauge == null || gauge.gaugeId != gaugeId) { | |
518 if ((gauge = findGaugeById(gaugeId)) == null) { | |
519 log.warn("Cannot find gauge for id " + gaugeId + "."); | |
520 continue; | |
521 } | |
522 } | |
523 | |
524 gauge.addMainValue(label, value); | |
525 } | |
526 | |
527 for (GaugeRange g: gauges) { | |
528 g.buildClasses(); | |
529 } | |
530 | |
531 return true; | |
532 } | |
533 | 603 |
534 protected void loadFixings(Session session) { | 604 protected void loadFixings(Session session) { |
535 SQLQuery query = session.createSQLQuery(SQL_FIXINGS) | 605 SQLQuery query = session.createSQLQuery(SQL_FIXINGS) |
536 .addScalar("wst_id", StandardBasicTypes.INTEGER) | 606 .addScalar("wst_id", StandardBasicTypes.INTEGER) |
537 .addScalar("description", StandardBasicTypes.STRING); | 607 .addScalar("description", StandardBasicTypes.STRING); |
572 for (Fixing fixing: fixings) { | 642 for (Fixing fixing: fixings) { |
573 fixing.loadColumnsKmRange(query); | 643 fixing.loadColumnsKmRange(query); |
574 } | 644 } |
575 } | 645 } |
576 | 646 |
577 protected void loadFixingsColumnsQRanges(Session session) { | 647 protected void loadFixingsColumnsQRanges( |
648 Session session, | |
649 GaugeFinder gaugeFinder | |
650 ) { | |
578 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) | 651 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) |
579 .addScalar("q", StandardBasicTypes.DOUBLE) | 652 .addScalar("q", StandardBasicTypes.DOUBLE) |
580 .addScalar("start_km", StandardBasicTypes.DOUBLE) | 653 .addScalar("start_km", StandardBasicTypes.DOUBLE) |
581 .addScalar("stop_km", StandardBasicTypes.DOUBLE); | 654 .addScalar("stop_km", StandardBasicTypes.DOUBLE); |
582 | 655 |
583 for (Fixing fixing: fixings) { | 656 for (Fixing fixing: fixings) { |
584 fixing.loadColumnsQRanges(query); | 657 fixing.loadColumnsQRanges(query, gaugeFinder); |
585 } | 658 } |
586 } | 659 } |
587 | 660 |
588 public boolean load(Session session) { | 661 public boolean load(Session session) { |
589 | 662 |
590 if (!loadRiver(session)) { | 663 if (!loadRiver(session) |
664 || !loadRiverExtent(session)) { | |
591 return false; | 665 return false; |
592 } | 666 } |
593 | 667 |
594 if (!loadRiverExtent(session)) { | 668 GaugeFinder gaugeFinder = loadGauges(session); |
595 return false; | 669 |
596 } | 670 if (gaugeFinder == null |
597 | 671 || !gaugeFinder.loadDischargeSectors(session, riverId)) { |
598 if (!loadGauges(session)) { | |
599 return false; | |
600 } | |
601 | |
602 if (!loadDischargeSectors(session)) { | |
603 return false; | 672 return false; |
604 } | 673 } |
605 | 674 |
606 loadFixings(session); | 675 loadFixings(session); |
607 loadFixingsColumns(session); | 676 loadFixingsColumns(session); |
608 loadFixingsColumnsKmRange(session); | 677 loadFixingsColumnsKmRange(session); |
609 loadFixingsColumnsQRanges(session); | 678 loadFixingsColumnsQRanges(session, gaugeFinder); |
610 | 679 |
611 return true; | 680 return true; |
612 } | 681 } |
613 | 682 |
683 private static final Range FULL_EXTENT = | |
684 new Range(-Double.MAX_VALUE, Double.MAX_VALUE); | |
685 | |
614 public void generateOverview(Document document) { | 686 public void generateOverview(Document document) { |
687 generateOverview(document, FULL_EXTENT); | |
688 } | |
689 | |
690 public void generateOverview(Document document, Range range) { | |
615 | 691 |
616 List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); | 692 List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); |
617 | 693 |
618 for (Fixing fixing: fixings) { | 694 for (Fixing fixing: fixings) { |
619 fixing.addAllColumns(allColumns); | 695 fixing.addAllColumns(allColumns, range); |
620 } | 696 } |
621 | 697 |
622 Collections.sort(allColumns, Fixing.DATE_CMP); | 698 Collections.sort(allColumns, Fixing.DATE_CMP); |
623 | 699 |
624 Element fixingsElement = document.createElement("fixings"); | 700 Element fixingsElement = document.createElement("fixings"); |
635 | 711 |
636 Element esE = document.createElement("events"); | 712 Element esE = document.createElement("events"); |
637 | 713 |
638 for (Fixing.Column column: allColumns) { | 714 for (Fixing.Column column: allColumns) { |
639 | 715 |
640 double km = isKmUp ? column.start : column.end; | 716 // TODO: Apply additional filters here. |
641 | 717 List<SectorRange> sectors = column.getSectors(); |
642 GaugeRange gauge = findGaugeByKm(km); | |
643 | |
644 if (gauge == null) { | |
645 log.warn("Cannot find gauge for km " + km + "."); | |
646 continue; | |
647 } | |
648 | |
649 List<SectorRange> sectors = column.classify(gauge); | |
650 | 718 |
651 if (!sectors.isEmpty()) { | 719 if (!sectors.isEmpty()) { |
652 Element eE = document.createElement("event"); | 720 Element eE = document.createElement("event"); |
653 eE.setAttribute("name", | 721 eE.setAttribute("name", |
654 String.valueOf(column.getFixing().description)); | 722 String.valueOf(column.getFixing().description)); |