comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 3814:8083f6384023

merged flys-artifacts/pre2.6-2012-01-04
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:56 +0200
parents d13be39cfd1d
children 16e74c5e636f
comparison
equal deleted inserted replaced
1491:2a00f4849738 3814:8083f6384023
1 package de.intevation.flys.artifacts;
2
3 import java.awt.geom.Point2D;
4
5 import de.intevation.artifactdatabase.ProtocolUtils;
6
7 import de.intevation.artifactdatabase.data.StateData;
8
9 import de.intevation.artifactdatabase.state.Facet;
10 import de.intevation.artifactdatabase.state.Output;
11 import de.intevation.artifactdatabase.state.State;
12 import de.intevation.artifactdatabase.state.StateEngine;
13
14 import de.intevation.artifactdatabase.transition.TransitionEngine;
15
16 import de.intevation.artifacts.CallContext;
17 import de.intevation.artifacts.Message;
18
19 import de.intevation.artifacts.common.ArtifactNamespaceContext;
20
21 import de.intevation.artifacts.common.utils.XMLUtils;
22 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
23
24 import de.intevation.flys.artifacts.context.FLYSContext;
25
26 import de.intevation.flys.artifacts.model.Calculation1;
27 import de.intevation.flys.artifacts.model.Calculation2;
28 import de.intevation.flys.artifacts.model.Calculation3;
29 import de.intevation.flys.artifacts.model.Calculation4;
30 import de.intevation.flys.artifacts.model.Calculation;
31 import de.intevation.flys.artifacts.model.CalculationResult;
32 import de.intevation.flys.artifacts.model.CrossSectionFactory;
33 import de.intevation.flys.artifacts.model.DischargeTables;
34 import de.intevation.flys.artifacts.model.FacetTypes;
35 import de.intevation.flys.artifacts.model.MainValuesFactory;
36 import de.intevation.flys.artifacts.model.Segment;
37 import de.intevation.flys.artifacts.model.WQKms;
38 import de.intevation.flys.artifacts.model.WstValueTable;
39 import de.intevation.flys.artifacts.model.WstValueTableFactory;
40
41 import de.intevation.flys.artifacts.states.DefaultState;
42 import de.intevation.flys.artifacts.states.LocationDistanceSelect;
43
44 import de.intevation.flys.geom.Lines;
45
46 import de.intevation.flys.model.Gauge;
47 import de.intevation.flys.model.River;
48 import de.intevation.flys.model.CrossSection;
49 import de.intevation.flys.model.CrossSectionLine;
50
51 import de.intevation.flys.utils.DoubleUtil;
52 import de.intevation.flys.utils.FLYSUtils;
53
54 import gnu.trove.TDoubleArrayList;
55
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collections;
59 import java.util.LinkedList;
60 import java.util.List;
61 import java.util.Map;
62
63 import org.apache.log4j.Logger;
64
65 import org.w3c.dom.Document;
66 import org.w3c.dom.Element;
67 import org.w3c.dom.Node;
68
69 import de.intevation.flys.artifacts.model.CalculationMessage;
70
71 /**
72 * The default WINFO artifact.
73 *
74 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
75 */
76 public class WINFOArtifact
77 extends FLYSArtifact
78 implements FacetTypes, WaterLineArtifact {
79
80 /** The logger for this class. */
81 private static Logger logger = Logger.getLogger(WINFOArtifact.class);
82
83 /** The name of the artifact. */
84 public static final String ARTIFACT_NAME = "winfo";
85
86 /** XPath */
87 public static final String XPATH_STATIC_UI ="/art:result/art:ui/art:static";
88
89 /** The default number of steps between the start end end of a selected Q
90 * range. */
91 public static final int DEFAULT_Q_STEPS = 30;
92
93 /** The default step width between the start end end kilometer. */
94 public static final double DEFAULT_KM_STEPS = 0.1;
95
96
97 /**
98 * The default constructor.
99 */
100 public WINFOArtifact() {
101 }
102
103
104 /**
105 * This method returns a description of this artifact.
106 *
107 * @param data Some data.
108 * @param context The CallContext.
109 *
110 * @return the description of this artifact.
111 */
112 public Document describe(Document data, CallContext context) {
113 logger.debug("Describe: the current state is: " + getCurrentStateId());
114
115 if (logger.isDebugEnabled()) {
116 dumpArtifact();
117 }
118
119 FLYSContext flysContext = FLYSUtils.getFlysContext(context);
120
121 StateEngine stateEngine = (StateEngine) flysContext.get(
122 FLYSContext.STATE_ENGINE_KEY);
123
124 TransitionEngine transitionEngine = (TransitionEngine) flysContext.get(
125 FLYSContext.TRANSITION_ENGINE_KEY);
126
127 List<State> reachable = transitionEngine.getReachableStates(
128 this, getCurrentState(context), stateEngine);
129
130 Document description = XMLUtils.newDocument();
131 XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
132 description,
133 ArtifactNamespaceContext.NAMESPACE_URI,
134 ArtifactNamespaceContext.NAMESPACE_PREFIX);
135
136 Element root = ProtocolUtils.createRootNode(creator);
137 description.appendChild(root);
138
139 State current = getCurrentState(context);
140
141 ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash());
142 ProtocolUtils.appendState(creator, root, current);
143 ProtocolUtils.appendReachableStates(creator, root, reachable);
144
145 appendBackgroundActivity(creator, root, context);
146
147 Element name = ProtocolUtils.createArtNode(
148 creator, "name",
149 new String[] { "value" },
150 new String[] { getName() });
151
152 Element ui = ProtocolUtils.createArtNode(
153 creator, "ui", null, null);
154
155 Element staticUI = ProtocolUtils.createArtNode(
156 creator, "static", null, null);
157
158 Element outs = ProtocolUtils.createArtNode(
159 creator, "outputmodes", null, null);
160 appendOutputModes(description, outs, context, identifier());
161
162 appendStaticUI(description, staticUI, context, identifier());
163
164 Element dynamic = current.describe(
165 this,
166 description,
167 root,
168 context,
169 identifier());
170
171 if (dynamic != null) {
172 ui.appendChild(dynamic);
173 }
174
175 ui.appendChild(staticUI);
176
177 root.appendChild(name);
178 root.appendChild(ui);
179 root.appendChild(outs);
180
181 return description;
182 }
183
184
185 /**
186 * Returns the name of the concrete artifact.
187 *
188 * @return the name of the concrete artifact.
189 */
190 public String getName() {
191 return ARTIFACT_NAME;
192 }
193
194
195 protected static void appendBackgroundActivity(
196 ElementCreator cr,
197 Element root,
198 CallContext context
199 ) {
200 Element inBackground = cr.create("background-processing");
201 root.appendChild(inBackground);
202
203 cr.addAttr(
204 inBackground,
205 "value",
206 String.valueOf(context.isInBackground()),
207 true);
208
209 LinkedList<Message> messages = context.getBackgroundMessages();
210
211 if (messages == null) {
212 return;
213 }
214
215 CalculationMessage message = (CalculationMessage) messages.getLast();
216 cr.addAttr(
217 inBackground,
218 "steps",
219 String.valueOf(message.getSteps()),
220 true);
221
222 cr.addAttr(
223 inBackground,
224 "currentStep",
225 String.valueOf(message.getCurrentStep()),
226 true);
227
228 inBackground.setTextContent(message.getMessage());
229 }
230
231
232 /**
233 * Append output mode nodes to a document.
234 */
235 protected void appendOutputModes(
236 Document doc,
237 Element outs,
238 CallContext context,
239 String uuid)
240 {
241 List<String> stateIds = getPreviousStateIds();
242
243 XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
244 doc,
245 ArtifactNamespaceContext.NAMESPACE_URI,
246 ArtifactNamespaceContext.NAMESPACE_PREFIX);
247
248 FLYSContext flysContext = FLYSUtils.getFlysContext(context);
249 StateEngine engine = (StateEngine) flysContext.get(
250 FLYSContext.STATE_ENGINE_KEY);
251
252 for (String stateId: stateIds) {
253 logger.debug("Append output modes for state: " + stateId);
254 DefaultState state = (DefaultState) engine.getState(stateId);
255
256 List<Output> list = state.getOutputs();
257 if (list == null || list.size() == 0) {
258 logger.debug("-> No output modes for this state.");
259 continue;
260 }
261
262 List<Facet> fs = facets.get(stateId);
263
264 if (fs == null || fs.size() == 0) {
265 logger.debug("No facets for previous state found.");
266 continue;
267 }
268
269 logger.debug("Found " + fs.size() + " facets in previous states.");
270
271 List<Output> generated = generateOutputs(list, fs);
272
273 ProtocolUtils.appendOutputModes(doc, outs, generated);
274 }
275
276 try {
277 DefaultState cur = (DefaultState) getCurrentState(context);
278 if (cur.validate(this)) {
279 List<Output> list = cur.getOutputs();
280 if (list != null && list.size() > 0) {
281 logger.debug(
282 "Append output modes for current state: " + cur.getID());
283
284 List<Facet> fs = facets.get(cur.getID());
285
286 if (fs != null && fs.size() > 0) {
287 List<Output> generated = generateOutputs(list, fs);
288
289 logger.debug("Found " + fs.size() + " current facets.");
290 if (!generated.isEmpty()) {
291 ProtocolUtils.appendOutputModes(
292 doc, outs, generated);
293 }
294 }
295 else {
296 logger.debug("No facets found for the current state.");
297 }
298 }
299 }
300 }
301 catch (IllegalArgumentException iae) {
302 // state is not valid, so we do not append its outputs.
303 }
304 }
305
306
307 /**
308 * This method appends the static data - that has already been inserted by
309 * the user - to the static node of the DESCRIBE document.
310 *
311 * @param doc The document.
312 * @param ui The root node.
313 * @param context The CallContext.
314 * @param uuid The identifier of the artifact.
315 */
316 protected void appendStaticUI(
317 Document doc,
318 Node ui,
319 CallContext context,
320 String uuid)
321 {
322 List<String> stateIds = getPreviousStateIds();
323
324 FLYSContext flysContext = FLYSUtils.getFlysContext(context);
325 StateEngine engine = (StateEngine) flysContext.get(
326 FLYSContext.STATE_ENGINE_KEY);
327
328 for (String stateId: stateIds) {
329 logger.debug("Append static data for state: " + stateId);
330 DefaultState state = (DefaultState) engine.getState(stateId);
331
332 ui.appendChild(state.describeStatic(this, doc, ui, context, uuid));
333 }
334 }
335
336
337 //
338 // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES
339 //
340
341 /**
342 * Returns the data that is computed by a waterlevel computation.
343 *
344 * @return an array of data triples that consist of W, Q and Kms.
345 */
346 public CalculationResult getWaterlevelData()
347 {
348 logger.debug("WINFOArtifact.getWaterlevelData");
349
350 River river = FLYSUtils.getRiver(this);
351 if (river == null) {
352 return error(new WQKms[0], "No river selected.");
353 }
354
355 double[] kms = getKms();
356 if (kms == null) {
357 return error(new WQKms[0], "No Kms selected.");
358 }
359
360 double[] qs = getQs();
361 double[] ws = null;
362 boolean qSel = true;
363
364 if (qs == null) {
365 logger.debug("Determine Q values based on a set of W values.");
366 qSel = false;
367 ws = getWs();
368 qs = getQsForWs(ws);
369 if (qs == null) {
370 return error(new WQKms[0], "conversion ws to qs failed.");
371 }
372 }
373
374 WstValueTable wst = WstValueTableFactory.getTable(river);
375 if (wst == null) {
376 return error(new WQKms[0], "No Wst found for selected river.");
377 }
378
379
380 double [] range = FLYSUtils.getKmRange(this);
381 if (range == null) {
382 return error(new WQKms[0], "No range found");
383 }
384
385 double refKm;
386
387 if (isFreeQ()) {
388 refKm = range[0];
389 logger.debug("'free' calculation (km " + refKm + ")");
390 }
391 else {
392 Gauge gauge = river.determineGaugeByPosition(range[0]);
393 if (gauge == null) {
394 return error(
395 new WQKms[0], "No gauge found for km " + range[0]);
396 }
397
398 refKm = gauge.getStation().doubleValue();
399
400 logger.debug(
401 "reference gauge: " + gauge.getName() + " (km " + refKm + ")");
402 }
403
404 return computeWaterlevelData(kms, qs, ws, wst, refKm);
405 }
406
407
408 /**
409 * Computes the data of a waterlevel computation based on the interpolation
410 * in WstValueTable.
411 *
412 * @param kms The kilometer values.
413 * @param qa The discharge values.
414 * @param wst The WstValueTable used for the interpolation.
415 *
416 * @return an array of data triples that consist of W, Q and Kms.
417 */
418 public static CalculationResult computeWaterlevelData(
419 double [] kms,
420 double [] qs,
421 double [] ws,
422 WstValueTable wst,
423 double refKm
424 ) {
425 logger.info("WINFOArtifact.computeWaterlevelData");
426
427 Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm);
428
429 return calc1.calculate(wst);
430 }
431
432
433 /**
434 * Returns the data that is computed by a duration curve computation.
435 *
436 * @return the data computed by a duration curve computation.
437 */
438 public CalculationResult getDurationCurveData() {
439 logger.debug("WINFOArtifact.getDurationCurveData");
440
441 River r = FLYSUtils.getRiver(this);
442
443 if (r == null) {
444 return error(null, "Cannot determine river.");
445 }
446
447 Gauge g = getGauge();
448
449 if (g == null) {
450 return error(null, "Cannot determine gauge.");
451 }
452
453 double[] locations = FLYSUtils.getLocations(this);
454
455 if (locations == null) {
456 return error(null, "Cannot determine location.");
457 }
458
459 WstValueTable wst = WstValueTableFactory.getTable(r);
460 if (wst == null) {
461 return error(null, "No Wst found for selected river.");
462 }
463
464 return computeDurationCurveData(g, wst, locations[0]);
465 }
466
467
468 /**
469 * Computes the data used to create duration curves.
470 *
471 * @param gauge The selected gauge.
472 * @param location The selected location.
473 *
474 * @return the computed data.
475 */
476 public static CalculationResult computeDurationCurveData(
477 Gauge gauge,
478 WstValueTable wst,
479 double location)
480 {
481 logger.info("WINFOArtifact.computeDurationCurveData");
482
483 Object[] obj = MainValuesFactory.getDurationCurveData(gauge);
484
485 int[] days = (int[]) obj[0];
486 double[] qs = (double[]) obj[1];
487
488 Calculation3 calculation = new Calculation3(location, days, qs);
489
490 return calculation.calculate(wst);
491 }
492
493
494 /**
495 * Returns the data that is used to create discharge curves.
496 *
497 */
498 public CalculationResult getDischargeCurveData() {
499
500 River river = FLYSUtils.getRiver(this);
501 if (river == null) {
502 return error(new WQKms[0], "no river found");
503 }
504
505 double [] distance = FLYSUtils.getKmRange(this);
506
507 if (distance == null) {
508 return error(new WQKms[0], "no range found");
509 }
510
511 List<Gauge> gauges = river.determineGauges(distance[0], distance[1]);
512
513 if (gauges.isEmpty()) {
514 return error(new WQKms[0], "no gauges found");
515 }
516
517 String [] names = new String[gauges.size()];
518
519 for (int i = 0; i < names.length; ++i) {
520 names[i] = gauges.get(i).getName();
521 }
522
523 DischargeTables dt = new DischargeTables(river.getName(), names);
524
525 Map<String, double [][]> map = dt.getValues(100d);
526
527 ArrayList<WQKms> res = new ArrayList<WQKms>();
528
529 for (Gauge gauge: gauges) {
530 String name = gauge.getName();
531 double [][] values = map.get(name);
532 if (values == null) {
533 continue;
534 }
535 double [] kms = new double[values[0].length];
536 Arrays.fill(kms, gauge.getStation().doubleValue());
537 res.add(new WQKms(kms, values[0], values[1], name));
538 }
539
540 return new CalculationResult(
541 res.toArray(new WQKms[res.size()]),
542 new Calculation());
543 }
544
545
546 /**
547 * Returns the data that is computed by a discharge curve computation.
548 *
549 * @return the data computed by a discharge curve computation.
550 */
551 public CalculationResult getComputedDischargeCurveData()
552 throws NullPointerException
553 {
554 logger.debug("WINFOArtifact.getComputedDischargeCurveData");
555
556 River r = FLYSUtils.getRiver(this);
557
558 if (r == null) {
559 return error(new WQKms[0], "Cannot determine river.");
560 }
561
562 double[] locations = FLYSUtils.getLocations(this);
563
564 if (locations == null) {
565 return error(new WQKms[0], "Cannot determine location.");
566 }
567
568 WstValueTable wst = WstValueTableFactory.getTable(r);
569 if (wst == null) {
570 return error(new WQKms[0], "No Wst found for selected river.");
571 }
572
573 return computeDischargeCurveData(wst, locations[0]);
574 }
575
576
577 /**
578 * Computes the data used to create computed discharge curves.
579 *
580 * @param wst The WstValueTable that is used for the interpolation.
581 * @param location The location where the computation should be based on.
582 *
583 * @return an object that contains tuples of W/Q values at the specified
584 * location.
585 */
586 public static CalculationResult computeDischargeCurveData(
587 WstValueTable wst,
588 double location)
589 {
590 logger.info("WINFOArtifact.computeDischargeCurveData");
591
592 Calculation2 calculation = new Calculation2(location);
593
594 return calculation.calculate(wst);
595 }
596
597 protected static final CalculationResult error(Object data, String msg) {
598 return new CalculationResult(data, new Calculation(msg));
599 }
600
601
602 /**
603 * Returns the data computed by the discharge longitudinal section
604 * computation.
605 *
606 * @return an array of WQKms object - one object for each given Q value.
607 */
608 public CalculationResult getDischargeLongitudinalSectionData() {
609
610 logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData");
611
612 River river = FLYSUtils.getRiver(this);
613 if (river == null) {
614 logger.debug("No river selected.");
615 return error(new WQKms[0], "No river selected.");
616 }
617
618 WstValueTable table = WstValueTableFactory.getTable(river);
619 if (table == null) {
620 logger.debug("No wst found for selected river.");
621 return error(new WQKms[0], "No wst found for selected river.");
622 }
623
624 List<Segment> segments = getSegments();
625
626 if (segments == null) {
627 logger.debug("Cannot create segments.");
628 return error(new WQKms[0], "Cannot create segments.");
629 }
630
631 double [] range = getFromToStep();
632
633 if (range == null) {
634 logger.debug("Cannot figure out range.");
635 return error(new WQKms[0], "Cannot figure out range.");
636 }
637
638 Calculation4 calc4 = new Calculation4(segments, river, isQ());
639
640 return calc4.calculate(table, range[0], range[1], range[2]);
641 }
642
643
644 public List<Segment> getSegments() {
645 StateData wqValues = getData("wq_values");
646 if (wqValues == null) {
647 logger.warn("no wq_values given");
648 return Collections.emptyList();
649 }
650 String input = (String)wqValues.getValue();
651 if (input == null || (input = input.trim()).length() == 0) {
652 logger.warn("wq_values are empty");
653 return Collections.emptyList();
654 }
655 return Segment.parseSegments(input);
656 }
657
658
659 /**
660 * Get List of all cross-sections for current river.
661 *
662 * @return List of CrossSections for current river, null in case of error.
663 */
664 protected List<CrossSection> getCrossSections() {
665 River river = FLYSUtils.getRiver(this);
666 if (river == null) {
667 logger.warn("No river in WINFO found");
668 return null;
669 }
670 return CrossSectionFactory.getCrossSections(river);
671 }
672
673
674 /**
675 * Get points of line describing the surface of water at cross section.
676 *
677 * @return an array holding coordinates of points of surface of water (
678 * in the form {{x1, x2} {y1, y2}} ).
679 */
680 public double [][] getWaterLines(int idx, CrossSectionLine csl) {
681 logger.debug("getWaterLines(" + idx + ")");
682
683 List<Point2D> points = csl.fetchCrossSectionLinesPoints();
684
685 // Need W at km
686 WQKms [] wqkms = (WQKms[]) getWaterlevelData().getData();
687 if (wqkms.length == 0) {
688 logger.error("No WQKms found.");
689 return Lines.createWaterLines(points, 0.0f);
690 }
691
692 if (wqkms.length < idx) {
693 logger.error("getWaterLines() requested index ("
694 + idx + " not found.");
695 }
696
697 // Find W at km, linear naive approach.
698 WQKms triple = wqkms[idx];
699
700 // Find index of km.
701 double wishKM = csl.getKm().doubleValue();
702 int old_idx = 0;
703
704 if (triple.size() == 0) {
705 logger.warn("Calculation of waterline is empty.");
706 return Lines.createWaterLines(points, 0.0f);
707 }
708
709 // Linear seach in WQKms for closest km.
710 double old_dist_wish = Math.abs(wishKM - triple.getKm(0));
711 double last_w = triple.getW(0);
712
713 for (int i = 0, T = triple.size(); i < T; i++) {
714 double diff = Math.abs(wishKM - triple.getKm(i));
715 if (diff > old_dist_wish) {
716 break;
717 }
718 last_w = triple.getW(i);
719 old_dist_wish = diff;
720 }
721 return Lines.createWaterLines(points, last_w);
722 }
723
724
725 /**
726 * Get name of cross sections.
727 * @return list of names of cross-sections.
728 */
729 public List<String> getCrossSectionNames() {
730 logger.debug("getCrossSectionNames");
731 List<String> names = new ArrayList<String>();
732
733 for (CrossSection section: getCrossSections()) {
734 names.add(section.getDescription());
735 }
736
737 return names;
738 }
739
740
741 /**
742 * Returns the Qs for a number of Ws. This method makes use of
743 * DischargeTables.getQForW().
744 *
745 * @param ws An array of W values.
746 *
747 * @return an array of Q values.
748 */
749 public double[] getQsForWs(double[] ws) {
750
751 boolean debug = logger.isDebugEnabled();
752
753 if (debug) {
754 logger.debug("FLYSArtifact.getQsForWs");
755 }
756
757 River r = FLYSUtils.getRiver(this);
758 if (r == null) {
759 logger.warn("no river found");
760 return null;
761 }
762
763 double [] range = FLYSUtils.getKmRange(this);
764 if (range == null) {
765 logger.warn("no ranges found");
766 return null;
767 }
768
769 if (debug) {
770 logger.debug("range: " + Arrays.toString(range));
771 }
772
773 Gauge g = r.determineGaugeByPosition(range[0]);
774 if (g == null) {
775 logger.warn("no gauge found for km: " + range[0]);
776 return null;
777 }
778
779 if (debug) {
780 logger.debug("convert w->q with gauge '" + g.getName() + "'");
781 }
782
783 DischargeTables dt = new DischargeTables(r.getName(), g.getName());
784 Map<String, double [][]> tmp = dt.getValues();
785
786 double[][] values = tmp.get(g.getName());
787 double[] qs = new double[ws.length];
788
789 for (int i = 0; i < ws.length; i++) {
790 qs[i] = dt.getQForW(values, ws[i]);
791 if (debug) {
792 logger.debug("w: " + ws[i] + " -> q: " + qs[i]);
793 }
794 }
795
796 return qs;
797 }
798
799
800 /**
801 * Determines the selected mode of distance/range input.
802 *
803 * @return true, if the range mode is selected otherwise false.
804 */
805 public boolean isRange() {
806 StateData mode = getData("ld_mode");
807
808 if (mode == null) {
809 logger.warn("No mode location/range chosen. Defaults to range.");
810 return true;
811 }
812
813 String value = (String) mode.getValue();
814
815 return value.equals("distance");
816 }
817
818
819 /**
820 * Returns the selected distance based on a given range (from, to).
821 *
822 * @param dFrom The StateData that contains the lower value.
823 * @param dTo The StateData that contains the upper value.
824 *
825 * @return the selected distance.
826 */
827 protected double[] getDistanceByRange(StateData dFrom, StateData dTo) {
828 double from = Double.parseDouble((String) dFrom.getValue());
829 double to = Double.parseDouble((String) dTo.getValue());
830
831 return new double[] { from, to };
832 }
833
834
835 /**
836 * Returns the selected Kms.
837 *
838 * @param distance An 2dim array with [lower, upper] values.
839 *
840 * @return the selected Kms.
841 */
842 public double[] getKms(double[] distance) {
843 StateData dStep = getData("ld_step");
844
845 if (dStep == null) {
846 logger.warn("No step width given. Cannot compute Kms.");
847 return null;
848 }
849
850 double step = Double.parseDouble((String) dStep.getValue());
851
852 // transform step from 'm' into 'km'
853 step = step / 1000;
854
855 if (step == 0d) {
856 step = DEFAULT_KM_STEPS;
857 }
858
859 return DoubleUtil.explode(distance[0], distance[1], step);
860 }
861
862
863 /**
864 * Returns the selected Kms.
865 *
866 * @return the selected kms.
867 */
868 public double[] getKms() {
869 if (isRange()) {
870 double[] distance = FLYSUtils.getKmRange(this);
871 return getKms(distance);
872
873 }
874 else {
875 return LocationDistanceSelect.getLocations(this);
876 }
877 }
878
879
880 public double [] getFromToStep() {
881 if (!isRange()) {
882 return null;
883 }
884 double [] fromTo = FLYSUtils.getKmRange(this);
885
886 if (fromTo == null) {
887 return null;
888 }
889
890 StateData dStep = getData("ld_step");
891 if (dStep == null) {
892 return null;
893 }
894
895 double [] result = new double[3];
896 result[0] = fromTo[0];
897 result[1] = fromTo[1];
898
899 try {
900 String step = (String)dStep.getValue();
901 result[2] = DoubleUtil.round(Double.parseDouble(step) / 1000d);
902 }
903 catch (NumberFormatException nfe) {
904 return null;
905 }
906
907 return result;
908 }
909
910
911 /**
912 * Returns the gauge based on the current distance and river.
913 *
914 * @return the gauge.
915 */
916 public Gauge getGauge() {
917 return FLYSUtils.getGauge(this);
918 }
919
920
921 /**
922 * Returns the gauges that match the selected kilometer range.
923 *
924 * @return the gauges based on the selected kilometer range.
925 */
926 public List<Gauge> getGauges() {
927
928 River river = FLYSUtils.getRiver(this);
929 if (river == null) {
930 return null;
931 }
932
933 double [] dist = FLYSUtils.getKmRange(this);
934 if (dist == null) {
935 return null;
936 }
937
938 return river.determineGauges(dist[0], dist[1]);
939 }
940
941
942 /**
943 * This method returns the Q values.
944 *
945 * @return the selected Q values or null, if no Q values are selected.
946 */
947 public double[] getQs() {
948 StateData dMode = getData("wq_mode");
949 StateData dSelection = getData("wq_selection");
950
951 String mode = dMode != null ? (String) dMode.getValue() : "";
952 String sel = dSelection != null ? (String)dSelection.getValue() : null;
953
954 if (mode.equals("Q")) {
955 if (sel != null && sel.equals("single")) {
956 return getSingleWQValues();
957 }
958 else {
959 return getWQTriple();
960 }
961 }
962 else {
963 logger.warn("You try to get Qs, but W has been inserted.");
964 return null;
965 }
966 }
967
968
969 public boolean isQ() {
970 StateData mode = getData("wq_mode");
971 return mode != null && mode.getValue().equals("Q");
972 }
973
974
975 /**
976 * Returns true, if the parameter is set to compute data on a free range.
977 * Otherwise it returns false, which tells the calculation that it is bound
978 * to a gauge.
979 *
980 * @return true, if the calculation should compute on a free range otherwise
981 * false and the calculation is bound to a gauge.
982 */
983 public boolean isFreeQ() {
984 StateData mode = getData("wq_free");
985 String value = (mode != null) ? (String) mode.getValue() : null;
986
987 logger.debug("isFreeQ: " + value);
988
989 if (value == null) {
990 return false;
991 }
992
993 return Boolean.valueOf(value);
994 }
995
996
997 /**
998 * Returns the Q values based on a specified kilometer range.
999 *
1000 * @param range A 2dim array with lower and upper kilometer range.
1001 *
1002 * @return an array of Q values.
1003 */
1004 public double[] getQs(double[] range) {
1005 StateData dMode = getData("wq_mode");
1006 StateData dValues = getData("wq_values");
1007
1008 String mode = (dMode != null) ? (String) dMode.getValue() : "";
1009
1010 if (mode.equals("Q")) {
1011 return getWQForDist(range);
1012 }
1013
1014 logger.warn("You try to get Qs, but Ws has been inserted.");
1015 return null;
1016 }
1017
1018
1019 /**
1020 * Returns the W values based on a specified kilometer range.
1021 *
1022 * @param range A 2dim array with lower and upper kilometer range.
1023 *
1024 * @return an array of W values.
1025 */
1026 public double[] getWs(double[] range) {
1027 StateData dMode = getData("wq_mode");
1028 StateData dValues = getData("wq_values");
1029
1030 String mode = (dMode != null) ? (String) dMode.getValue() : "";
1031
1032 if (mode.equals("W")) {
1033 return getWQForDist(range);
1034 }
1035
1036 logger.warn("You try to get Ws, but Qs has been inserted.");
1037 return null;
1038 }
1039
1040
1041 /**
1042 * This method returns the W values.
1043 *
1044 * @return the selected W values or null, if no W values are selected.
1045 */
1046 public double[] getWs() {
1047 StateData dMode = getData("wq_mode");
1048 StateData dSingle = getData("wq_single");
1049
1050 String mode = (dMode != null) ? (String) dMode.getValue() : "";
1051
1052 if (mode.equals("W")) {
1053 if (dSingle != null) {
1054 return getSingleWQValues();
1055 }
1056 else {
1057 return getWQTriple();
1058 }
1059 }
1060 else {
1061 logger.warn("You try to get Qs, but W has been inserted.");
1062 return null;
1063 }
1064 }
1065
1066 /**
1067 * This method returns the given W or Q values for a specific range
1068 * (inserted in the WQ input panel for discharge longitudinal sections).
1069 *
1070 * @param dist A 2dim array with lower und upper kilometer values.
1071 *
1072 * @return an array of W or Q values.
1073 */
1074 protected double[] getWQForDist(double[] dist) {
1075 logger.debug("Search wq values for range: " + dist[0] + " - " + dist[1]);
1076 StateData data = getData("wq_values");
1077
1078 if (data == null) {
1079 logger.warn("Missing wq values!");
1080 return null;
1081 }
1082
1083 String dataString = (String) data.getValue();
1084 String[] ranges = dataString.split(":");
1085
1086 for (String range: ranges) {
1087 String[] parts = range.split(";");
1088
1089 double lower = Double.parseDouble(parts[0]);
1090 double upper = Double.parseDouble(parts[1]);
1091
1092 if (lower <= dist[0] && upper >= dist[1]) {
1093 String[] values = parts[2].split(",");
1094
1095 int num = values.length;
1096 double[] res = new double[num];
1097
1098 for (int i = 0; i < num; i++) {
1099 try {
1100 res[i] = Double.parseDouble(values[i]);
1101 }
1102 catch (NumberFormatException nfe) {
1103 logger.warn(nfe, nfe);
1104 }
1105 }
1106
1107 return res;
1108 }
1109 }
1110
1111 logger.warn("Specified range for WQ not found!");
1112
1113 return null;
1114 }
1115
1116
1117 /**
1118 * This method returns an array of inserted WQ triples that consist of from,
1119 * to and the step width.
1120 *
1121 * @return an array of from, to and step width.
1122 */
1123 protected double[] getWQTriple() {
1124 StateData dFrom = getData("wq_from");
1125 StateData dTo = getData("wq_to");
1126
1127 if (dFrom == null || dTo == null) {
1128 logger.warn("Missing start or end value for range.");
1129 return null;
1130 }
1131
1132 double from = Double.parseDouble((String) dFrom.getValue());
1133 double to = Double.parseDouble((String) dTo.getValue());
1134
1135 StateData dStep = getData("wq_step");
1136
1137 if (dStep == null) {
1138 logger.warn("No step width given. Cannot compute Qs.");
1139 return null;
1140 }
1141
1142 double step = Double.parseDouble((String) dStep.getValue());
1143
1144 // if no width is given, the DEFAULT_Q_STEPS is used to compute the step
1145 // width. Maybe, we should round the value to a number of digits.
1146 if (step == 0d) {
1147 double diff = to - from;
1148 step = diff / DEFAULT_Q_STEPS;
1149 }
1150
1151 return DoubleUtil.explode(from, to, step);
1152 }
1153
1154
1155 /**
1156 * Returns an array of inserted WQ double values stored as whitespace
1157 * separated list.
1158 *
1159 * @return an array of W or Q values.
1160 */
1161 protected double[] getSingleWQValues() {
1162 StateData dSingle = getData("wq_single");
1163
1164 if (dSingle == null) {
1165 logger.warn("Cannot determine single WQ values. No data given.");
1166 return null;
1167 }
1168
1169 String tmp = (String) dSingle.getValue();
1170 String[] strValues = tmp.split(" ");
1171
1172 TDoubleArrayList values = new TDoubleArrayList();
1173
1174 for (String strValue: strValues) {
1175 try {
1176 values.add(Double.parseDouble(strValue));
1177 }
1178 catch (NumberFormatException nfe) {
1179 logger.warn(nfe, nfe);
1180 }
1181 }
1182
1183 values.sort();
1184
1185 return values.toNativeArray();
1186 }
1187
1188
1189 /**
1190 * Determines Facets initial disposition regarding activity (think of
1191 * selection in Client ThemeList GUI). This will be checked one time
1192 * when the facet enters a collections describe document.
1193 *
1194 * @param facetName name of the facet.
1195 * @param index index of the facet.
1196 * @return 0 if not active
1197 */
1198 @Override
1199 public int getInitialFacetActivity(String outputName, String facetName, int index) {
1200 String [] inactives = new String[] {
1201 LONGITUDINAL_Q,
1202 DURATION_Q
1203 };
1204
1205 logger.debug("WINFOArtifact.active?: "
1206 + outputName
1207 + "/"
1208 + facetName);
1209
1210 if (facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) ||
1211 facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_W)
1212 && outputName.equals("computed_discharge_curve"))
1213 {
1214 return 0;
1215 }
1216 return Arrays.asList(inactives).contains(facetName)
1217 ? 0
1218 : 1;
1219 }
1220 }
1221 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org