Mercurial > dive4elements > river
changeset 3786:4adc35aa655c
merged flys-artifacts/2.9.1
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:47 +0200 |
parents | e82acd5c86f7 (current diff) a5f65e8983be (diff) |
children | 69d19995bc3c |
files | |
diffstat | 611 files changed, 120077 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/ChangeLog Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,20966 @@ +2012-09-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java: + Removed superfluous imports. + +2012-09-19 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java: + New. CSV exporter for bed quality calculation result. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java: + Added getter with km as parameter. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Added facet for csv export. + + * doc/conf/artifacts/minfo.xml: + Added output mode. + + * doc/conf/conf.xml: + Added export generator. + +2012-09-19 Björn Ricks <bjoern.ricks@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java: + Return also the station in a service response. + +2012-09-18 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java: + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java: + A and B facets of fix analysis are now deactivated by default (#717). + +2012-09-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeCalculation.java: + Extract parameters needed for calculation from access. + + * src/main/java/de/intevation/flys/utils/DoubleUtil.java(isValid): + Added method to check if 2d double array is valid. + +2012-09-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use generics aware Collections.emptyList(). + +2012-09-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java, + src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java, + src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java, + src/main/java/de/intevation/flys/exports/OutputHelper.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java, + src/main/java/de/intevation/flys/themes/ThemeMapping.java, + src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + The usual whitespace and import cleanups. + +2012-09-18 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java: + Avoid loading empty data sets. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java: + Load bedload data sets... + +2012-09-18 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java: + Removed incorrect characteristic diameter. + +2012-09-18 Christian Lins <christian.lins@intevation.de> + + * doc/conf/default-themes.xml: + Update point themes of fixing W/Q chart to show point descriptions + per default (#685). + +2012-09-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + i18n for area label (fix issue487). + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Get internationalized label and numberformat, pass it to renderer, + where its used. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Area label translations. + +2012-09-18 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Add robustness checks to prevent NPEs (#859). + +2012-09-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Brought showarea-theme setting back (fix issue865). + + * doc/conf/default-themes.xml, doc/conf/second-themes.xml: + Define showarea theme prop where its needed. + +2012-09-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java: + Added setter for date range. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java + Set correct date range for result. + +2012-09-17 Raimund Renkert <raimund.renkert@intevation.de> + + Refactor MINFO bed quality resultsets and facets. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java, + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java: + Removed. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java: + Container wrapping the single calculation results. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityDiameterResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java: + New. Results containing calculated average diameter, porosity and density. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java: + Facets now return the concrete datatype using the facet index. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Create a facet for each resultset. + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java: + Use the classes containing the results. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java: + Use new classes for results and calculate porosity and density once + each period. + +2012-09-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added still missing + translations for state. + +2012-09-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added missing translations + for state to select soundings. + + * src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java: + Added more debug output to find out how many single and epochs where + found. + +2012-09-17 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml: Defined initial colors. + + * src/main/java/de/intevation/flys/exports/OutputHelper.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java, + src/main/java/de/intevation/flys/themes/ThemeMapping.java: Added more + debug output to understand why theme mappings don't match to facets. + +2012-09-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java: + Extract characteristic diameter only if the user selected a diameter. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java: + Calculate for selected diameter only. + +2012-09-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java, + src/main/java/de/intevation/flys/artifacts/model/SQOverview.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java: + Fixed wrong assigned loggers. + +2012-09-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java: + Please _DO NOT_ use FLYSUtils in new code based on Access*! + Now the river name is fetch via access.getRiver(). + + * src/main/java/de/intevation/flys/artifacts/access/RiverAccess.java: + New. Almost all calculations need accessing the river name. + + * src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java, + src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FixAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java, + src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java: + Now extend RiverAccess. + +2012-09-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java: + Implemented the access methods needed for + "Auslagerung extremer Wasserspiegellagen". + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java: + Move segment parsing to DoubleUtil to be usable with more data types. + The wire protocol should be the same for: + - "WINFO: W fuer ungleichwertige Abfluesse", + - "WINFO: Auslagerung extremer Wasserspiegellagen" + - "Fixierungsanalyse: Auslagerung von Wasserspiegellagen" + + * src/main/java/de/intevation/flys/utils/DoubleUtil.java: + Now contains the the code to parse segments. Found segments + are propagated back with a callback. + + * src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java: + Added toString() method. + +2012-09-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + More infrastructure stuff for the "Auslagerung extremer Wasserspiegellagen". + + * src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeCalculation.java: + New. Stub for "Auslagerung extremer Wasserspiegellagen" calculation. + + * src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeResult.java: + New. Stub for the cacheable results of the calculation. + + * src/main/java/de/intevation/flys/artifacts/states/extreme/ExtremeCompute.java: + New. Stub compute state for the calculation. + + * src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java: + New. Sub access to the artifact to extract the relevant data. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + A little code reordering to keep related stuff together more closely. + +2012-09-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java, + src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java, + src/main/java/de/intevation/flys/artifacts/FixationArtifact.java: + Removed some superfluous implementations of FacetTypes. + TODO: FacetTypes should be broken into smaller pieces. + ATM a lof of class implement it and share a lot of unnecessary + stuff. + +2012-09-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java, + src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java: + Deleted. Some nice code from the early days of the cross sections + but its unused nowadays. + +2012-09-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java: + Removed superfluous imports. + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java, + src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java, + src/main/java/de/intevation/flys/exports/minfo/BedQualityInfoGenerator.java, + src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java: + Removed trailing whitespace. + +2012-09-15 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java, + src/main/java/de/intevation/flys/utils/Formatter.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + i18n messages are now formatted with correct (client) locale, not + server VM locale (#852).. + +2012-09-15 Christian Lins <christian.lins@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml, + doc/conf/artifacts/manualpoints.xml, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Try to add support for ManualPoints in fixing charts (not working yet). + +2012-09-14 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java: + Fixed SQL-statement. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java: + Added getter for all kms. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java: + Implemented the bed quality calculation. There are still some fixes to do, + e.g. extract a single result object for porosity and density. + +2012-09-14 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java: + Getter for characteristic diameter. + +2012-09-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Create i18n facet descriptions. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New i18n strings for facets + in bed quality calculation. + +2012-09-14 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Splitted facets for diameter of bed into + two facets: diameter for sublayer and toplayer. + + * doc/conf/themes.xml, + doc/conf/second-themes.xml, + doc/conf/default-themes.xml: Splitted themes for diameter of bed into + two themes. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Splitted facets for diameter of bed into two facets. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java: + New method to retrieve the diameter data. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java: + New methods to retrieve the porosity, density and diameter data. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Create two facets for bed diameter instead of a single one. + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java: + Insert data supported by facets into chart. + +2012-09-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: Added function to + generate a randomized line. + +2012-09-14 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Defined new mappings for the six bed quality + facets. + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml: Added themes for new mappings in + themes.xml. The themes in second-themes are the same as in + default-themss. + +2012-09-14 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java: + Updated bed quality result objects. + +2012-09-14 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Splitted porosity and density facets into + two facets: a toplayer and a sublayer facet for each. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + the new facets for toplayer and sublayer for porosity and density. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Create Facets based on the calculation results. + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java: + Use concrete result types in doXXXOut(). + +2012-09-13 Christian Lins <christian.lins@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml, + doc/conf/themes.xml, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java: + Work on ManualPoints integration in fix analysis charts (wip). + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Fix missing import. + +2012-09-13 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java: + Added getter for calculation parameters. + + * src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java: + Removed. Moved to package de.intevation.flys.artifacts.model.minfo. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java: + New. Calculation results and some more calculation stub. + +2012-09-13 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeState.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Renamed MINFO parameter + 'main.channel' -> 'main_channel' and 'total.channel' -> 'total_channel'. + +2012-09-13 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java: + Added depth parameter to bed quality data. + +2012-09-13 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Registered new OutGenerators BedQualityGenerator and + BedQualityInfoGenerator. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java: + New Facets for serving data for bed quality exports/charts. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Add some dummy Facets to force chart creation. + + * src/main/java/de/intevation/flys/exports/minfo/BedQualityInfoGenerator.java, + src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java: + New OutGenerators for bed quality charts. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New I18N strings for bed + quality charts. + +2012-09-13 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java: + The factory can load bedload and bed data from seddb now. + +2012-09-13 Raimund Renkert <raimund.renkert@intevation.de> + + Objects and factory for minfo bedquality calculation data. + + * src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java: + New. Data objects and factory for minfo bed quality calculation. + +2012-09-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added missing images for datacage config manual doc. + + * doc/datacage-config-manual/figures/bsh_logo.png, + doc/datacage-config-manual/figures/intevation-logo.eps, + doc/datacage-config-manual/figures/intevation-logo.pdf: + Logos for DC conf doc. + +2012-09-13 Björn Ricks <bjoern.ricks@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java: + Add also min and max q values to the river info. + +2012-09-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java, + src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java: + Removed trailing whitespace. + +2012-09-12 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java, + src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverview.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverviewFactory.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverviewFactory.java: + New. Services, data structures and factories for overview charts in minfo + bed quality calculation. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityPeriodsSelect.java: + New. State for period input in minfo bed quality that displays the overview + charts. + + * doc/conf/artifacts/minfo.xml: + Added states and transitions for minfo bed quality calculation. + + * doc/conf/conf.xml: + Added services. + +2012-09-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java, + src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java, + src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Removed trailing whitespace. + +2012-09-12 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Defined facets for bed quality chart. + + * src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java: + Calculation stub for bed quality. + + * src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java: + Access stub for bed quality data. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + facets defined in minfo.xml. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java: + Override computeAdvance; no calculation and facet creation takes place + yet. + +2012-09-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java: + Made AEo and datum attributes NPE proof. + +2012-09-11 Björn Ricks <bjoern.ricks@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java: + Use getGaugeValue method also for aeo and datum. Also add some javadoc for + the getGaugeValue method. + +2012-09-11 Christian Lins <christian.lins@intevation.de> + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Fix for line text annotations in Delta W(t) charts (#837). + +2012-09-10 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java: + Add additional check to prevent NPE (fix for #844) + +2012-09-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java: + Extends Range now. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Adjusted to use slightly different method names of Range. + +2012-09-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Range.java: + Added disjoint method. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: + Find a list of segments intersecting a given range. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Generate a list of ranges needed for the input of Qs + in the "Auslagerung extremer Wasserspiegellagen.". + +2012-09-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java: + Added type safety. + +2012-09-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Java 1.5 -> 1.6 + +2012-09-10 Christian Lins <christian.lins@intevation.de> + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml: + Remove unnecessary attributes for fixation derived curve (#836). + +2012-09-10 Björn Ricks <bjoern.ricks@intevation.de> + + * doc/conf/conf.xml, + src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java: + Add new artifact service for the gauge overview + +2012-09-09 Christian Lins <christian.lins@intevation.de> + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml, + doc/conf/virtual-themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java: + Theme transparency attribute support (part of #840). + +2012-09-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java: + Store Ws and Qs in double arrays instead of WQ objects (as + they are return from WstValueTable.interpolateTabular()). + This simplifies the code and should be more memory effective. + +2012-09-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Linear.java: + Added a vectorwise weighting. + + src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Added methods to interpolate tabulated values only. + Need in "Auslagerung extremer Wasserspiegellagen". + +2012-09-09 Christian Lins <christian.lins@intevation.de> + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml, + doc/conf/virtual-themes.xml: + Updating themes for issue #840 (wip). + +2012-09-09 Christian Lins <christian.lins@intevation.de> + + * doc/conf/second-themes.xml: + Modify every theme to differ from default theme (#835). + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java: + Use gauge.getMainValues() instead of gauge.fetchMainValues() which fixes + a compiling issue on my setup. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Some models for representing results for the upcoming + "Auslagerung extremer Wasserspiegellagen". Work im progress. + + * src/main/java/de/intevation/flys/artifacts/math/NaNFunction.java: + New. Function always return NaNs. + + * src/main/java/de/intevation/flys/artifacts/math/UnivariateRealFunctionFunction.java: + New. Adapter to bridge between our Functions and UnivariateRealFunctions + of Apache Common Math. + + * src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java: + New. Part of the result model of "Auslagerung extremer Wasserspiegellagen". + Its a function for a given km that uses a spline interpolation + for the tabulated Q range (which is effectively the same as the + calculated discharge curve for this km) and an extrapolated + function beyond the tabulated values. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/themes/DefaultTheme.java: + More iterator code simplification. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/themes/DefaultThemeField.java: + Simplified code. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java: + Simplified code. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java: + Improved robustness and performance. + Only expose date events as Collections not TreeSets. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QW.java: + New. a pure model for discharge and waterlevel. No extras. + + Makes reuse in upcoming "Auslagerung extremer Wasserspiegellagen" + a lot easier. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java: + Removed. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWI.java: + Re-inserted here. Extends the new QW and adds all the extra bells + and whistles needed in the fixings analysis. + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java, + src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingResult.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Adjusted QW to QWI. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java; + Removed because code is found in backend already. + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java: + Simplified. Please _DO_NOT_ use NullPointerExceptions for regular flow control! + This hides unintended errors. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Removed code duplication. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Removed trailing whitespace. + +2012-09-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java: + Removed superfluous imports. + +2012-09-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java, + src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/java/de/intevation/flys/artifacts/ChartArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixATExport.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/TypeSection.java, + src/main/java/de/intevation/flys/jfree/DoubleBounds.java, + src/main/java/de/intevation/flys/jfree/Bounds.java: + Cosmetics, docs. + +2012-09-07 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/minfo.xml: + Add data fields for characteristic bed and bedload diameter. + + * src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java: + Use parametermatrix as UI provider and set the correct data. + + * src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java, + src/main/java/de/intevation/flys/artifacts/states/MultiStringArrayState.java: + Updated method parameter. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-09-07 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 791. + + * src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java: + Add start km to data to compare reference and target km in next state. + +2012-09-07 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 2.9 + +2012-09-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java: + Removed superfluous imports. + +2012-09-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java: + Removed the deprecated method. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Call the new Gauge model method fetchDurationCurveData(). + +2012-09-06 Björn Ricks <bjoern.ricks@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java: + Mark getDurationCurveData as deprecated. The instance method of Gauge with + the same name should be used instead. + +2012-09-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Revert accidentally committed experiment. + +2012-09-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Comments, changed order of columns as requested in issue825. + +2012-09-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java: + Only goto down to Q = 0.0001 to circumvent some numerial issues + with steep functions around zero. + +2012-09-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java: + Increase Q max about 5% (as it should be). + +2012-09-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for issue687 + + * src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java: + Rewrote AT export to fix it. + +2012-09-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix for issue820. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Changed label for middle height/depth. + +2012-09-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Default horizontal and vertical placement of logo to "center" and + "top" instead of "none." + +2012-09-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Improved comment regarding image placement. + +2012-09-03 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Fixed URLs for logos. + +2012-09-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue744 (wrong ranges for w/q input). + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Do not add items for gauges that do not intersect with given range. + +2012-09-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue829 (wrong fixation names). + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Fix check, column indices start with 0. + +2012-09-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java, + src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java: + Removed trailing whitespace. + +2012-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Fix cast. + +2012-08-31 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for minfo bed quality parameters. + +2012-08-31 Björn Ricks <bjoern.ricks@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/ModuleService.java, + src/main/java/de/intevation/flys/artifacts/model/Module.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties, + doc/conf/conf.xml: + Add a module service. It's now possible to configure the modules which are + available for a client. With the selected attribute it is possible to give + a hint for the client which module should be pre selected by default. + +2012-08-31 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java, + src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java: + New. States for minfo bed quality calculation. + + * doc/conf/artifacts/minfo.xml: + Added states and transitions for minfo bed quality calculation. + +2012-08-31 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Refactored state to use FLYSArtifact instead of WINFOArtifact. + +2012-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue817 (double datacage entries). + + * doc/conf/meta-data.xml: removed double entries. + +2012-08-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + issue729, default line labels for waterlines in cross sections. + + * doc/conf/default-themes.xml: Default line label and level label + to true for lines in crossections.. + +2012-08-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + issue814, line labels do not follow zoom. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Move line label into visible area if otherwise outside. + +2012-08-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + issue695, show waterlevel as line label. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Fix path to showlevel style property. + +2012-08-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Mention how/where to change predefined logos in comment. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Mention how/where to change predefined logos in comment, + Use resource for images. + + * src/main/resources/images/bfg_logo.gif, + src/main/resources/images/intevation.png: + Added sample logos of intevation and bfg. + +2012-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Copy and slightly modified XYChartGenerators logo mechanism. + +2012-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (getLeftX, getRightX): New and overridden to deal with inverted axis + for logo placement in longitudinalsection charts. + +2012-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Use RectangleAnchor to set anchor of logo. + +2012-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Add Logo settings to CrossSection ChartSettings. + +2012-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Split logo-placement property in two, one for horizontal, one for + vertical placement. + + * src/main/java/de/intevation/flys/exports/ChartSettings.java, + src/main/java/de/intevation/flys/exports/ChartSection.java: + Accessors for split property. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java + (logoHPlace,logoVPlace,logoPlace): Use split properties for vertical + and horizontal placement of logo. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Use split properties, respect in placement. + +2012-08-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Sloppy logo placement property implementation. + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: + Parse and set logo placement property value. + + * src/main/java/de/intevation/flys/exports/ChartSection.java: + Accessors for Logo placement property. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java + (logoPlace): New, get logo placement property value. + (showLogo): Default to "none". + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Sloppy interpretation of the logo placement property. + +2012-08-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (addLogo): New, add an image annotation to plot, very stubby, + use hard-coded paths for now. + +2012-08-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Preparations for logo-inclusion in charts. + + * src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java: + New string attribute type to trigger different UI (selectboxes) + in client. + + * src/main/java/de/intevation/flys/exports/TypeSection.java + (setChoiceStringValue): Create new ChoiceStringAttribute. + + + * src/main/java/de/intevation/flys/exports/ChartSection.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartSettings.java: + Accessors to show logo-property. + +2012-08-28 Raimund Renkert <raimund.renkert@intevation.de> + + MINFO: Implemented UI and facet/artifact stack for bed height differences. + + * src/main/java/de/intevation/flys/artifacts/model/minfo, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java, + src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java, + src/main/java/de/intevation/flys/artifacts/model/StaticBedHeightCacheKey.java: + New. Facet and data object incl. factory for bed heights. + + * src/main/java/de/intevation/flys/artifacts/states/minfo, + src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java, + src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java, + src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java: + New. States for difference calculation mode and new artifact for difference + selection. + + * src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java: + Added getter for time (year or epoch). + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new facet type. + + * doc/conf/meta-data.xml: + Datacage config for minfo bed heights. + + * doc/conf/artifacts/minfo.xml: + Added transitions and states for minfo difference calculation. + + * doc/conf/conf.xml: + Added artifact factory. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-08-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartSettings.java: + (setDisplayGird, setDisplayGrid): Fixed typos. + +2012-08-23 Raimund Renkert <raimund.renkert@intevation.de> + + FixA: Changed sector average form point to line in delta W(t) chart. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Add data points for sector average and changed time unit for analysis period + from month to day. + + * doc/conf/default-themes.xml: + Changed theme for sector average to color line. + +2012-08-23 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 716. FixA: Spilt reference and analysis period themes into one theme for each event. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java: + Create a facet for each event and use new facet for sector average in + longitudinal section chart. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java: + The facets now return data for a single event. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAvSectorFacet.java: + New. This facet returns an analysis period containing the calculated + average. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java: + Added methods to get the dates for all reference and analysis period events. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Fixed range combining. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Adjusted generators to use the data returned by the facets. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Using trove to map int->int instead of bloated generics. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Prevent another NPE. Removed dead code. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Each analysis period has its own index scheme now. + +2012-08-22 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Fix for NullPointerException. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Made indices of analysis periods QWs zero based. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java: + Store index, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + Adjusted to keep constructors in sync. + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Set QD index to the values of the column cache columns. + +2012-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Use the column cache to establish a consistent index scheme. + TODO: Store the index values in the created QWDs. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + doFitting() fetches the columns from column cache, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Reuse same column cache from fitting to have the same index scheme. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Adjusted to use the column cache. + +2012-08-22 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Fix NullPointerExceptions in cross section diagrams that occurred when + no HYKs are available for the selected kms. + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: + Typo, see issue #806 + +2012-08-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixATExport.java: + Removed superfluous import. s/Double.valueOf/Double.parseDouble/. + +2012-08-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixATExport.java: + Removed debug outputs. + +2012-08-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixATExport.java: + New. Exporter for FixAnaylsis AT files. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java: + Add facet for AT export. + + * doc/conf/conf.xml: + Added out generator for fix AT export. + + * doc/conf/artifacts/fixanalysis.xml: + Added outputmode for AT export. + +2012-08-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Add more facets to + compat list, removed doubled wq output. + +2012-08-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Shorten overlong lines. Simplified code. + +2012-08-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Interpolate and reduce WQKms if currentKm found in context. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Handle WQKms in WQOuts. + +2012-08-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Add longitudinal section + facet type to compatibility list of W/Q diags. + +2012-08-16 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java: + Added getter for ui provider. + +2012-08-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + BasicStroke constructor takes an float as first argument + so there is no need to blow up an 'int' to an Integer + which is auto-unboxed to int which is implicitly cast to float. + +2012-08-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Do not hard-recommend gauge-dis. for fixwq. + +2012-08-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java: + Fail more gracefully. + +2012-08-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: More former calculations in fixA (dwt) DC. + +2012-08-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: More former calculations in fixA DC. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Add discharge curve facet to + compat. list. + + * doc/conf/meta-data.xml: Show discharge curves for FixA WQ DC. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Handle discharge curve data. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Add more facets to compat. list. + + * doc/conf/meta-data.xml: Show more additional data in FixA w/q-diag. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Handle new, annotation-type facets. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Added wqkms facets to comp. list. + + * doc/conf/meta-data.xml: Add wq-basedata and other stubs to fixA dc. + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java + (getWQAtKm): Adjusted behaviour such that passed km can be + respected. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Handle WQFacets. + + * src/main/java/de/intevation/flys/artifacts/model/WQFacet.java: + Pass contexts current_km if available. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Added deltawt-out. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Show former calculations in FixA WQ-DC. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Show more former calculations in DeltaWTs + and fix query (and/or/() precedences). + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Show more former calculations in fixA LS. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Renamed qsector(s) factory. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Load annotations for fixA long.sections. + Add stubs for "old calculations"-dc-conf for various FixA outs. + + * src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Handle annotation outs. + +2012-08-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml, doc/conf/default-themes.xml: + Added theme fields for qsectors label. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Add markers for the qsectors. + +2012-08-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml, doc/conf/default-themes.xml: + Fix some typos, correct defaults and add mapping for qsector-theme. + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Cosmetics. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Add accidentally omitted change, stub for style-handling. + +2012-08-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/states/QSectorSingleState.java, + src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java: + Wording and i18n of qsectors. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Add Markers to plot for qsectors. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + i18n for qsectors. + +2012-08-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/QSectorSingleState.java: + New, accidentally omitted single state of a qsector-artifact. + +2012-08-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Add qsectors-facet to + compatibility list. + + * doc/conf/conf.xml: Register qsector artifact and its factory. + + * doc/conf/meta-data.xml: Recommend qsectors in fix w/q settings. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Add qsector facet type. + +2012-08-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/qsector.xml: + Trivial state model for qsector artifact. + + * src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java: + Rather trivial facet to get QSectors from QSectorArtifact. + + * src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java: + New QSectorArtifact. + +2012-08-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Cosmetics. + +2012-08-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java, + src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java: + Removed superfluous imports. + +2012-08-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Set info attribute (will evaluate as tooltip + in GUI. + +2012-08-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Reflect fact that there can be only one reference station. + +2012-08-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue798. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Set Tick Units dependant on cm/m scale on X axis. + +2012-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue748 + + * src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java, + src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java: + Only remove one data point per outlier removal iteration. + +2012-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Outlier.java: + Only evict only one(!) data point as outlier. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Recalculate the function when one point is removed. + +2012-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Outlier.java: + Corrected the formulas of Grubbs' test for outliers. + TODO: Remove only one(!) data point. Currently it removes + more than on point without recalculating the fitting curve. + This leads to too much removed points. + +2012-07-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Setup better initial activity for the facets of the S/Q results. + +2012-07-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Use getCurrentKmFromRequest().doubleValue() in i18n formatting. + +2012-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + getCurrentKmFromRequest returns Double(!) not double. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Use Double.parseDouble() instead od Double.valueOf(). + +2012-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Initially activate/deactivate facets. + +2012-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Refactored to use the new Chain-of-responsibility pattern in facet + activation. + +2012-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java: + Made expensive XMLUtils.toString() debug output conditional. + +2012-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Use the new infrastructure to figure out if a facet should + be initially active or not. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Uses the FacetActivity.Registry to look up the initial acitiviy. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Do not use sub classing any more. + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/HYKArtifact.java: + Register to FacetActivity.Registry now. TODO: Make it configurable. + +2012-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java, + src/main/java/de/intevation/flys/collections/CollectionAttribute.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/ChartArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/MapArtifact.java: + s/container.size() == 0/container.isEmpty()/ + +2012-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Lowered logging output level from info to debug. + Made some more debug outputs conditional. + +2012-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Some code simplifications. + +2012-07-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Extented the result data model of the S/Q calculation to + store the curve coefficients for each iteration step + of the outlier elimination. The starting data set of S/Qs + is stored as well. + + TODOs: + - Create the new facets as inactive. + - Repair the facet to style mapping. + + * doc/conf/themes.xml: Added mappings for new facets. + + * doc/conf/artifacts/minfo.xml: Configured the new facets. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java: + Adjusted to new data model. + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Generate facets for outlier curves and measurements. Simplified code. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + New facet types for outlier curves and meassurements. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + New set() method to set an array of values by their names. + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java: + Removed trailing whitespace. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java: + Adjusted to new data model. Curves are drawn over the whole length of the + starting S/Q dataset. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierCurveFacet.java: + New. Facet for the curves of the outlier test iterations. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierMeasurementFacet.java + New. Facet for the meassurement data remainind after outlier test iteration. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Now creates the new data model. + + * src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java, + src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java: + Refactorted to have more control over the data structures to be generated. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java: + The new data model to represnt a fraction result. Each outlier test iteration + results in a different iteration object. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for new facets. + +2012-07-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QWDDateRange.java: + Added method getQWD() to retrieve the QWD property. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Avoid class cast exceptions; a QWDDateRange object is returned by WQ + sector average Facet - not a QWD object. Use new getter method to + retrieve the required data object. + +2012-07-27 Ingo Weinzierl <ingo@intevation.de> + + Tagged module as '2.8.1'. + +2012-07-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QWDDateRange.java: + New class. QWD and a DateRange. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Produce QWDDateRanges in state, consume in generator. + +2012-07-26 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Registered new Output + 'fix_vollmer_wq_curve'. + + * doc/conf/conf.xml: Registered new FixWQCurveGenerator for + 'fix_vollmer_wq_curve'. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added new names for Facets + used in 'fix_vollmer_wq_curve' Output. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java: + Make use of FitResult (parent of FixAnalysisResult) which is enough for + these Facets instead of casting the calculation result to + FixAnalysisResult. + + * src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java: + Fixed potential NullpointerException. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Create new Facets for WQ curve, fix events and outliers. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Add subtitles only if the required data (date period and referenence + period) are existing. Otherwise do not add a subtitle. + +2012-07-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n strings (vollmer). + +2012-07-26 Christian Lins <christian.lins@intevation.de> + + * doc/conf/virtual-themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeAccess.java, + src/main/java/de/intevation/flys/themes/TextStyle.java, + src/main/java/de/intevation/flys/themes/LineStyle.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java, + src/main/java/de/intevation/flys/themes/PointStyle.java, + src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java, + src/main/java/de/intevation/flys/jfree/XYStyle.java, + src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java: + Line labels and point labels share same styles and code. + Point labels can have a background color. + +2012-07-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n strings (vollmer). + +2012-07-26 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Registered new Output + 'fix_waterlevel_export' for FixRealizingCompute State. + + * doc/conf/conf.xml: Registered new WaterlevelExport Generator for + 'fix_waterlevel_export'. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Create proper CSV, WST and PDF Facets with hash and State id. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Made + WaterlevelExporter support FixRealizingResult objects. + +2012-07-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWaterlevelFacet.java: + Removed instanceof hack to fetch the WQKms of the fix realizations. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWaterlevelFacet.java: + New. Subclass of WaterlevelFacet. Used to fetch the WQKms the fix realization way. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Create the subclassed waterlevel facets. + +2012-07-25 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Create proper facets for Ws and Qs. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Also add Q-Facet. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Add WaterlevelFacet. + + * doc/conf/artifacts/fixanalysis.xml: + Add output and facet compability. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java: + Fix data names in FixRealizingAccess. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Handle slightly different access to Fixation-WQKms. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Handle slightly different access to Fixation-WQKms. + +2012-07-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java: + Fix (last?) vol(l)mer naming issue. + +2012-07-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StateFactory.java, + src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + src/main/java/de/intevation/flys/themes/ThemeMapping.java: + s/.equals("")/.length() == 0/ + +2012-07-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java, + src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java, + src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed some superfluous casts. + +2012-07-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Removed some inner whitespace. + +2012-07-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + New base class for fixing analysis results. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingResult.java: + Inherits from FixResult. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Calculation returns FixRealizingResult. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Remove superfluous import. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Cosmetics. + +2012-07-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Broke over long line. + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java: + Added some getters. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Calculated the Q -> Ws. TODO: Produce result. + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n strings (vollmer). + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java: + Set ld_mode so that FLYSUtils can use it. + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n strings (vollmer). + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Handle FixationArtifacts with as much care as WINFOArtifacts, + by using refactore FLYSUtils. + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Towards per-Gauge-input of W/Q values for FixationArtifact. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java: + (getGauges): Refactored, moved from WINFOArtifact to FLYSUtils. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Handle unlucky differences in names of data for + WINFOArtifact/FixationArtifact. + + * doc/conf/artifacts/fixanalysis.xml: + (Re-)use WQAdapted State for fix.analysis. + +2012-07-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml, + src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java, + src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Cosmetics, docs. + +2012-07-23 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Moved code to convert W to Q at gauge to segments to be reusable. + +2012-07-23 Christian Lins <christian.lins@intevation.de> + + * doc/conf/themes.xml, + doc/conf/second-themes.xml, + doc/conf/default-themes.xml: + Remove line style attributes from FixingReferenceEvents theme. + +2012-07-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java + src/main/java/de/intevation/flys/artifacts/model/Segment.java: + Moved reference point comparator to segment class be be reusable + in FixA 'ausgelagerte Wasserspiegellagen'. + +2012-07-23 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Simplify annotation code. + +2012-07-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Made abstract. Sub classes have to overwrite innerCalculate() + calculate() now figures out the fixings overview and the function + to fit and passes it to innerCalculate() + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Overrides innerCalculate() now. + +2012-07-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Prevent NPE in getOutputForState(). Why does this happen? + +2012-07-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Made curve fitting over the given calculation range reusable. Removed dead code. + +2012-07-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Moved more common code into base class. + +2012-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: Clip the displayed from/to ranges + of the gauges to the max extent of the events. + +2012-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: Embed german and english translations + into the stylesheet. This should be better done by importing + an external resource depending on the choosen locale! + +2012-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: Introduced i18n to transformation. + +2012-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Wrong epsilon was taken so sector aggregation was not working + leading to too large result documents and wrong range display + on client side. + +2012-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: Render the names of the gauges into + the header line. Full name and spread is displayed as a tooltip. + +2012-07-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Use SQPeriodSelect state for the input of + a time range. The difference to PeriodSelect is the UI provider desired + by this state. + + * src/main/java/de/intevation/flys/artifacts/states/sq/SQPeriodSelect.java: + New subclass of PeriodSelect; this state wants to be rendered in a + 'sq.period.select' UI provider. + +2012-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: To help developing the + HTML overview stylsheet more quickly bring back in sync with + version of the flys-client. + +2012-07-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Changed the parameters for SQ relation + period selection; only a single period is allowed now. + + * src/main/java/de/intevation/flys/artifacts/states/PeriodSelect.java: New + class that allows the selection of a time period. + + * src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java: + Reduced support of time periods to a single period. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Adapted the usage of SQRelationAccess which method signature has + changed; it returns a single DateRange instance only. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Modified the keys of the + state for SQ relation time period input. + +2012-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java: + Disabled legends in this overview. + +2012-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java: + Removed superfluous imports. + +2012-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/messages_de.properties, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties: + Fixed anomalies. + +2012-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReportGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java, + src/main/java/de/intevation/flys/exports/OutGenerator.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Added a setCollection() method that allows the caller of OutGenerators + to set a reference to a FLYSArtifactCollection. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Use setCollection() to set the reference to the current + FLYSArtifactCollection before using OutGenerators. + + * doc/conf/conf.xml: Registered the SQOverviewGenerator. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Add a list of gauges which intersect the range of the selected columns: + + <fixings> + <gauges from="..." to="..." name="..."/> + ... + <gauges from="..." to="..." name="..."/> + </fixings> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java: + Store the name of the gauge, too. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java: + Load the names of the gauges from database, too. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Some minor refactoring. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Call super constructor to retrieve the common data from the artifact. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + New. Common base class for Fix*Calculations. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Moved common stuff to base class FixCalculation. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + Inherit from FixCalculation. + + * src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java: + Extract parameters that are only relevant for the + 'Ausgelagerte Wasserspiegellagen' calculation. + + isQ(): Must we convert the given values from W to Q first? + Used data field: 'fix_isq' + getSegments(): Segments same semantics as WINFO's + 'W fuer ungleichwertige Abfluesse.' + Used data field: 'fix_segments' + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java, + src/main/java/de/intevation/flys/artifacts/access/FixAccess.java: + Cosmetics. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/FixAccess.java: + New. Common base class for the Fix*Access. + + * src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java: + Now inherit from FixAccess. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java: + Prevent NPE. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java: + Use constant to lookup column instead of dynamically allocated array. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Removed. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java: + Re-added here. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java, + src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java, + src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Adjusted. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java: + New. Stub for 'Ausgelagerte Wasserspiegellagen' calculation. + + * src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java: + New. Stub for accessing the artifact to extract the relevant parameters + for the 'ausgelagerte Wasserspiegellagen' calculation. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Call the calculation if the state is reached. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Removed trailing whitespace. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java: + Deleted. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java: + Re-added here. + + * doc/conf/artifacts/fixanalysis.xml: Adjusted. BTW: Vollmer is spelled with two 'l's. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Removed. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java: + Re-added. + + * doc/conf/artifacts/fixanalysis.xml: Adjusted. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Deleted + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java: + Re-added. + + * src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Adjusted class name usage. + +2012-07-19 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + native2ascii with properties files. + Show analysis periods as subtitle in W/Q chart. + +2012-07-19 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Add subtitle to Fix W/Q chart. + Move addSubtitle() code from generators up to ChartGenerate which saves + a lot of duplicate code. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: + Deleted. + + * src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java: + Re-added. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Adjusted class name usage. + +2012-07-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Sourced code to set default values of a parameter to an own method. + Subclasses should override this method. + + * src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java: + Set default value for outliers to "3". + +2012-07-19 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Add kilometer info to chart titles. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java, + src/main/java/de/intevation/flys/exports/ChartSettings.java, + src/main/java/de/intevation/flys/jfree/XYStyle.java: + Use Integer.parseInt() instead of Integer.valueOf() + Autounboxing. + +2012-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Replaced "string -> object -> native -> object" by simple "string -> object". + Removed stupid duplicate XPathing. + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java: + Use only blue as point color. + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Adjusted Delta W(t) CSV exporter to customers wishes. + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Reordered columns, removed description, added W and formatted date + via i18n. + + * src/main/java/de/intevation/flys/utils/Formatter.java: + Added method to get a formatter based on pattern and locale. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n strings. + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Classify each discharge range by the gauges which intersect it. + + * src/main/java/de/intevation/flys/artifacts/model/Range.java: + Added convinience constructor. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java: + Added method to return all gauges. + +2012-07-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Use bandwidth parameter for width of band, adjusted name to be + displayed in legend. + +2012-07-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/default-themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Change bandwidth type to double (still bugged, round integers still + work, though). + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Added column for time range. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties + src/main/resources/messages_en.properties + src/main/resources/messages_de.properties: + Added i18n strings. + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Fixed stupid formatting bug. + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Added discharge column. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added missing strings. + +2012-07-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Removed trailing whitespace. + +2012-07-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java, + src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java, + src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java, + src/main/java/de/intevation/flys/collections/CollectionAttribute.java: + Cosmetics, doc. + +2012-07-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial implementation of issue720 (bandwith for curves), in + longitudinal section ws only, no styling, integer-based. + + * doc/conf/default-themes.xml: Add bandwidth to fields of longitudinal + section facets. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Add bandwidth + theme parsing. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + If bandwidth is set, add an area data series with datapoints + above/under the actual data points. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Helper for adding points with offset. + +2012-07-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java: + Use Q_BPEGEL as symbolic name for Q + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Out commented the LEFT JOINs which produce a lot of empty and + redundant data. Bring them back in when we treat subsamples right. + +2012-07-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added getValue() method. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Store location of calculation in result, too. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java: + Added method getTotalCount() to return the number of used S/Q pairs. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: + Store location of result, too. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java: + Write parameters as export result. + +2012-07-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + Bit of doc. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + TODO for automatic official lines added. + +2012-07-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Out commented debug output which caused OOM errors. + +2012-07-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/SQOverview.java, + src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Q is not taken from MESSUNG.Q but from MESSUNG.Q_BPEGEL + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java: + Fixed indentation. More macros. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Removed trailing whitespace. + +2012-07-16 Ingo Weinzierl <ingo@intevation.de> + + * Tagged module as '2.8'. + +2012-07-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StyledXYSeries.java, + src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java, + src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java, + src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/SQRelation.java, + src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java, + src/main/java/de/intevation/flys/artifacts/states/PeriodsSelect.java, + src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java, + src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java, + src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java, + src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java, + src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java, + src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WQFacet.java: + Removed same package imports. + +2012-07-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Lowered log level. + +2012-07-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow manual loading of official lines in + longitudinal_discharge diagrams. + +2012-07-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Prevent nasty NPE (hidden by autobox). + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Suppress data points with values <= 0 because they kill JFreeChart's + log/log diagrams. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Fixed more SQL syntax errors. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Generate more than one SQResult (To my big suprise it's possible). + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java. + src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Made more NPE bullet proof. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Fixed problem with string operation precedence. + +2012-07-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: very basic official lines matching the current + artifact (for this it is wrongly placed in previous calc.-part, for + now. + +2012-07-13 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: + Create shapefile directory instead of shapefile 'file'. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java, + src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java: + Removed translation whitespace. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java: + Finally! SQResult is build and should be ready for display. :-) + +2012-07-13 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java, + src/main/java/de/intevation/flys/utils/GeometryUtils.java: + Fix and workaround NullPointerExceptions. + +2012-07-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java, + src/main/java/de/intevation/flys/wsplgen/FacetCreator.java, + src/main/java/de/intevation/flys/wsplgen/JobObserver.java, + src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java, + src/main/java/de/intevation/flys/wsplgen/Scheduler.java, + src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java, + src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/artifacts/MapArtifact.java, + src/main/java/de/intevation/flys/utils/MapfileGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java: + Organized and added missing imports. + +2012-07-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Added new + functions to reproject an Envelope from one CoordinateReferenceSystem to + antoher. + + * src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java: + The getExtent() method will now return the extent of the layer in the + coordinate reference system that is configured for the specific river. + +2012-07-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java, + src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WSPLGENLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/WSPLGENReportFacet.java: + Moved to subpackage map. + + * src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/map/WMSLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENJob.java, + src/main/java/de/intevation/flys/artifacts/model/map/WMSDBLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENReportFacet.java: + Moved from upper package. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java, + src/main/java/de/intevation/flys/exports/OutputHelper.java, + src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java: + Added missing vim lines. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java, + src/main/java/de/intevation/flys/exports/OutputHelper.java: + Removed trailing whitespace. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed superfluous imports. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Only use first period of the time periods given by the UI. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: + Added some more index checking. + +2012-07-13 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java: + New. Facet for chart overview in sq relation. + + * src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java: + New. Generator for chart overview. This generator is not used jet. + Currently we generate the overview on client side by putting all charts in a + simple grid, cause the charts rendered by this generator are empty. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new Facet type. + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Add facets for overview. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Avoid a NPE in legend entry aggregation. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Moved log output to avoid NPE. + + * doc/conf/artifacts/minfo.xml: + Added new output for chart overview. + +2012-07-13 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Refactored. Moved some functionality to FLYSContext and OutputHelper. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: + Added 'getOutGenerator' to get a concrete generator. Moved from + FLYSArtifactCollection. + + * src/main/java/de/intevation/flys/exports/OutputHelper.java: + New. Provides the 'doOut' functionality for FYLSArtifactCollection. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java: + Handle the error case of accessing wrong indexed SQ relation + more smoothly. + +2012-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java: + Added access to the data of GSIEBSATZ and SSIEBUNG. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Added the left joins to the GSIEBSATZ and SSIEBUNG tables. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Do not store null values from database. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java: + New. Container for measurements. Helps to extract the S/Q fractions. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Now uses the measurements container. + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java: + Added convenience methods to extract the different fractions. + DONE: Q, S_SS, S_SF + TODO: S_BL_S, S_BL_FG, S_BL_CG, S_BL + + * src/main/java/de/intevation/flys/artifacts/model/SQOverview.java, + src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Relax existence of SIEBSATZID. + We have to use a left join during data extraction anyway. + We force the existence of Q because we cannot do the fitting if + we don't have them. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java: + New. Access to the data from the SedDB. + + * src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java: + Load measurements from SedDB. + + * src/main/java/de/intevation/flys/artifacts/model/SQOverview.java: + Force NOT NULL for discharge values, too. + + * src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java: + Indentation fix. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Iterate over all given periods. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java: + Fixed wrong logger class. + +2012-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + src/main/java/de/intevation/flys/artifacts/model/SQOverview.java: + Filter out the meassures which don't have a related 'Siebsatz'. + + doc/conf/cache.xml: Added forgotten cache for sq-overview. + + src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java: + Added vim line. + +2012-07-12 Christian Lins <christian.lins@intevation.de> + + * doc/conf/default-themes.xml, + doc/conf/virtual-themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Add showpointlabel style attribute. Refactor some styles to make use of + general attributes in the virtual themes. + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java, + src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Suppress or fix some warnings. + +2012-07-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Fix class name. + +2012-07-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java, + src/main/java/de/intevation/flys/exports/ChartExportHelper.java, + src/main/java/de/intevation/flys/exports/WstWriter.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java, + src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Various cosmetic doc fixes. + +2012-07-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Make official lines available in dc for + manual loading in longitudinal sections. + +2012-07-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Sieve.java: + Simulates a sieve to separate the differen fractions from each other. + +2012-07-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DateRange.java, + src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Removed trailing whitespace. + +2012-07-11 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DateRange.java, + src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Delta W(t) chart subtitle now with real values and correct i18n. + + +2012-07-11 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Re-add HYK rendering code again to CrossSectionGenerator (fix for #712). + + +2012-07-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java, + src/main/java/de/intevation/flys/artifacts/model/SQOverview.java: + Removed superfluous imports. + +2012-07-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/SQOverview.java: + Made km separating of dates epsilon tolerant and avoid empty date lists. + +2012-07-10 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java: + New. Service that generates an overview chart for measuring points. + + * src/main/java/de/intevation/flys/artifacts/model/SQOverview.java: + New. Instance of measuring points overview data. + + * src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java: + New. Foctory for overview data objects. + + * doc/conf/conf.xml: + Added new service to config. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-07-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix for issue694. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Also resolve edge cases (last/first cross section km). + +2012-07-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix for issue694 (Heightmarks snap to nearest cross section + line). + + * src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java: + Extended signature of getWaterLines to allow behaviour of only + delivering data if it snaps to the km (is closest). + + * src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Documentation, updated signature of getWaterLines(). + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Remember if Heightmarks are displayed, if so deliver data + only if cross-section is closest (snap). + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Make next and previous km of cross-sections available as data. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Provide next and previous cross-section km via blackboard, adjusted + call to getWaterLines. + +2012-07-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Removed trailing whitespace. + +2012-07-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ChartExportHelper.java, + src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/OutGenerator.java, + src/main/java/de/intevation/flys/exports/FlowVelocityGenerator.java: + Fix various documentation issues. + +2012-07-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java, + src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesExporter.java, + src/main/java/de/intevation/flys/exports/ChartHelper.java, + src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java, + src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java, + src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Fix various issues in the hard-to-find documentation. + +2012-07-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * pom.xml: Configure javadoc mojo to include doc for protected/private. + +2012-07-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/themes2html.xsl: Create a list of direct sub themes + of a theme. + +2012-07-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage-config-manual/Makefile: New, added Makefile. + +2012-07-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation2.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java, + src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/jfree/HasLabel.java: + Cosmetics, docs. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java: + Fixed XPath typo. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed dynamic XPaths to pervent potential XPath injections. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/themes2html.xsl: New. Transformation to get a better + overview of themes.xml. Usage: + + $ xsltproc --path doc/conf \ + contrib/themes2html.xsl \ + doc/conf/themes.xml \ + > themes.xhtml + + Use browser to view the resulting file. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/second-themes.xml: Name the second themegroup 'second' + instead of 'default' to avoid clashes with the real 'default' + themegroup. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/default-themes.xml, + doc/conf/virtual-themes.xml, + doc/conf/themes.xml, + doc/conf/second-themes.xml: + Added xml processing instruction. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/InvLog.java, + src/main/java/de/intevation/flys/artifacts/access/Access.java, + src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorA.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorB.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorC.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorD.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorE.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorF.java, + src/main/java/de/intevation/flys/exports/ChartArea.java, + src/main/java/de/intevation/flys/jfree/StyledValueMarker.java, + src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java: + Added vim lines. + +2012-07-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java, + src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java, + src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java: + Replaced tabs with four spaces each. + +2012-07-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartArea.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Removed superfluous imports. + +2012-07-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java, + src/main/java/de/intevation/flys/jfree/StyledValueMarker.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Removed trailing whitespace. + +2012-07-06 Christian Lins <christian.lins@intevation.de> + + * doc/conf/*-themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/jfree/StyledValueMarker.java, + src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Add styles for W(t) domain markers. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Remove false @override. + +2012-07-06 Christian Lins <christian.lins@intevation.de> + + * doc/conf/themes.xml, + doc/conf/second-themes.xml, + doc/conf/default-themes.xml: + Add missing themes for fixation charts. + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue705 (names for mainvalues in export). + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Documentation and use NamedMainValues irrespective of WQ-type ( + single vs range). + +2012-07-06 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + W(t) chart label rotation now working (see #684) + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Removed solved TODO. + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue710 (crashing diagrams with only one point). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Expand the range/bounds where its added. + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java + (expandPointRange): Fix weird code with help of new ChartHelper + method. + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartHelper.java + (expandBounds): New, expand bounds by given percentage. + +2012-07-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Distance.java: + New distance helper module. + +2012-07-06 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Remove debugging code. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Remove HYK references and code. + +2012-07-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage-config-manual/datacage-config-manual.tex: + Changed inclusions to include new content file. + + * doc/datacage-config-manual/content.tex: Content from doc/datacage.txt, + xml formatted. + +2012-07-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage-config-manual/datacage-config-manual.tex, + doc/datacage-config-manual/README, + doc/datacage-config-manual/title.tex: + Added stub of tex-version of datacage config documentation. + +2012-07-05 Christian Lins <christian.lins@intevation.de> + + * doc/*-themes.xml: + Add textorientation field. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartArea.java: + Move annotation related code to base class ChartGenerator. + +2012-07-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Prevent casting exception. + +2012-07-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + issue487 (wrong area calculation). + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Fix area calculation. + +2012-07-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Moved theme groups to own XML files to improve the + structure. + + * doc/conf/second-themes.xml, + doc/conf/default-themes.xml, + doc/conf/virtual-themes.xml: New XML files for themes / theme groups; each + theme group in one single file. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Improved logging; print number of theme groups and themes in it as INFO. + +2012-07-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Only show labels if enabled in theme. Commented (failed) trials to get the + text rotation right. + +2012-07-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Fix certain AIOOBs that were caused by the fact that QWDs can end up in two + different series. + +2012-07-03 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Implemented mergeRanges to combine y bounds in timeseries charts. + +2012-07-03 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveInfoGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtInfoGenerator.java: + New. Added chart info generator for WQ and delta W(t) chart. + + * doc/conf/conf.xml: + Added info generators to config. + +2012-07-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Very basic, unstyled, always-on labels of points in DeltaWt-Diagrams. + +2012-07-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Replaced Arrays.asList(new String[] { "a", "b" }).contains("a") code. + +2012-07-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/themes.xml, + src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java, + src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java, + src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java, + src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java: + Removed trailing whitespace. + +2012-07-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added missing themes for middle bed height curves. + +2012-07-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java, + src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java: + New Access objects to access relevant information of Artifacts specific + to bed heights and flow velocity calculations. + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java, + src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java, + src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java, + src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java: + Use *Access objects to get required information from Artifact. + + * src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Moved + methods to access specific information for calculations to *Access + objects. + +2012-07-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue695 (labeling of waterlines). + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + (doCrossSectionWaterLineOut): Handle labels more individually. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java + (applyShowLineLabel): Tell renderer that there is something to do in case + any label is switched on. + +2012-07-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/DifferenceCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java, + src/main/java/de/intevation/flys/artifacts/geom/Lines.java, + src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java, + src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeAccess.java, + src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java: + Fixed various bugs (package declarations, moved classes to correct + places). + +2012-07-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Removed line properties from fixation point themes + and added missing point properties. + +2012-07-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Cosmetics. + +2012-07-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + issue654. + + * src/main/java/de/intevation/flys/exports/LegendProcessor.java: + Do not include type in hash for legend item. + +2012-07-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java: + Generate CSV for facet 'fix_parameters'. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Be more eloquent on which kind of facet the exporter does not + like. + +2012-07-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Made it more symmetrical to FixationCompute. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Removed fake result stuff. Fetch parameters from SQRelationAccess. + +2012-07-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java: + Remove some evidence that the authors of this software + do not know Java at all. + +2012-07-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Part of flys/issue687 + + * src/main/java/de/intevation/flys/exports/ATWriter.java: + New. Samples fitting function to AT files. + + !!! Untested and expected to be slightly broken. !!! + + * src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java: + Made some formatting things public to be reusable. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for AT headers. + +2012-07-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifact-db.xml, + doc/conf/cache.xml, + doc/conf/meta-data.xml: Removed trailing whitespace. + +2012-07-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Removed embedded class IdGenerator. + + * src/main/java/de/intevation/flys/utils/IdGenerator.java: + New. Re-added the id generator as top level class. + +2012-06-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Added parameter exporter for fixings analysis. + Part of flys/issue689 + + * src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java: + New. Exports the contents of the parameters of the fix analysis. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added visitor interface to visit all rows of the parameters. + + * doc/conf/artifacts/fixanalysis.xml: Added new facet for + parameter export. + + * doc/conf/conf.xml: Register the new parameter exporter. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added facet type. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Fixed indentation. + Removed some programming oddities. + Create facet for parameter export. + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Removed code which is already contained in the base class. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Cleaned up code. + +2012-06-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + Deleted + + * src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java: + Re-added here + + * doc/conf/conf.xml: Adjusted package name of DeltaWtExporter. + +2012-06-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveInfoGenerator.java: + New. Added chart info companion for FixDerivedCurveGenerator. + + * doc/conf/conf.xml: Added to configuration. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java: + Code clean up. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixFunction.java: + Simplified. Not Serializable any more because its only a transient object. + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java: + Clean up. Simplified. Removed dependency from Function2DAdapter because + we are doing our own sampling. + + * src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionInfoGenerator.java: + Removed empty last line. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Small cosmetics. + + * src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Do not notify listeners when add data series. + + * src/main/java/de/intevation/flys/jfree/Function2DAdapter.java: + Removed. Obsolete. + +2012-06-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Removed superfluous import. + +2012-06-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionInfoGenerator.java: + New. Added chart info companion for FixLongitudinalSectionGenerator. + + * doc/conf/conf.xml: Added to configuration. + +2012-06-29 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Unfinished work on generalizing annotations in ChartGenerators. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: + Fixed parameter name. + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: + Fixed typo. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java: + Finished the access to the S/Q relation stuff. + + * doc/conf/artifacts/minfo.xml: + State "state.minfo.sq.periods" returns the value as string + symmetrical to state "state.fix.analysisperiods". + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java: + Deleted. + + * src/main/java/de/intevation/flys/artifacts/model/DateRange.java: + Re-added here because its of use not only in the fix analysis + but also in the S/Q relation. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java, + src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java, + src/main/java/de/intevation/flys/artifacts/access/Access.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Adjusted the imports for the moved DateRange. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java: + New. Artifact access for the S/Q relation. TODO: Add more parameters. + + * src/main/java/de/intevation/flys/artifacts/access/Access.java: + Remove trailing whitespace. + + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: + Added more debug output. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/Access.java: New. + Base class for *Access of FLYSArtifacts. + + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: + Extends Access now. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: + Removed dead code. + +2012-06-28 Christian Lins <christian.lins@intevation.de> + + * doc/conf/themes.xml, + src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Set text orientation to horizontal for points in Fixation W/Q curve. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Fix overlapping indices of facets. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Added method to figure out which discharge sectors of the + the analysis periods really contains data. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Only emit analysis period / discharge sectors which really contain data. + +2012-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Moved FixationArtifactAccess into own package access because there are + more *Access to come e.g. SQRelationAccess. + + TODO: Refactor the code for WINFO to use this *Access pattern. This + results in much cleaner, better scaling and better understandable code. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: Deleted. + * src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: New. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/access, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Adjusted imports. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Removed superfluous imports. + +2012-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + If fitting fails for tolerance of 1e-10 increase it incremental + by factor of 10 to 1e-3 and only bail out if it fails on this level. + +2012-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java: + Fixed da/dQ but the fitting still does not work for the function. :-/ + +2012-06-27 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Show only dates as point labels. + +2012-06-27 Christian Lins <christian.lins@intevation.de> + + * doc/conf/conf.xml: + Fix typo in generator class for fix_longitudinal_section_curve + +2012-06-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Create and handle new manual line facets. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Added new constructor to play nice with upcoming facet-type. + + * src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java: + Added functionality to serve as WaterLineFacet (calculate water + line against cross section profile). + + * src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java: + Extended to generate cross section water line facets, too. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Handle new Facet Type. + +2012-06-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + FacetType for upcoming cross_section.manualline facet. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added Facet Type and IS-helper dor upcoming facet. + +2012-06-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Configure Themes and compatibility of upcoming + cross_section.manualline facet. + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/manualpoint.xml: + Add upcoming facet to compatibility lists. + + * doc/conf/themes.xml: Register theme for upcoming facet. + +2012-06-27 Christian Lins <christian.lins@intevation.de> + + * doc/conf/conf.xml: + Add output generator for 'fix_derived_curve' + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Add some ugly formatted point labels. + +2012-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Moved describe() and the generating of output into FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + This the base class so it should contain common code! + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/FixationArtifact.java, + src/main/java/de/intevation/flys/artifacts/ChartArtifact.java, + src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/MapArtifact.java: + Moved common code into base class. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Removed superfluous imports. + +2012-06-27 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Use JFreeUtil.sampleFunction2D() to sample a StyledXYSeries. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + Add ctor with addtional custom facet index parameter. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Introduce IdGenerator to generate unique facets IDs within an output, + so themes can now be applied properly to points and lines. + +2012-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: + Removed some expensive XPath usage. Some quick profiling + showed that up to 7% of our code (excluding Hibernate, H2, Restlet, etc.) + were spend in these XPaths. A lot of time + + !!! Please, please, dear fellow programmers do not use XPath for fetching + !!! trivial things that are easily accessible via DOM, too! + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java, + src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java: + Refactored to better fit the data types of SQResult. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/LegendProcessor.java: + Removed trailing whitespace. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQ.java: + Added method to validate point. + + * src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java: + Added method to callback to re-initialize the function to fit. + + * src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java: + New. Shell for fitting of one SQ fraction. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Removed superfluous import. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java: + New. Specialized outlier test for the S/Q relation. + Outliers are accepted in multiples of the standard deviation. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Only generate outlier facet when we done the prepocessing. + +2012-06-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Enable legend aggregation in time series charts. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Call super.aggregateLegendEntries. + +2012-06-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Legend Item Aggregation refactoring. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java + (aggregateLegendEntries): Moved up from XYChartGenerator to ChartGenerator. + +2012-06-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Legend Item Aggregation refactoring. + + * src/main/java/de/intevation/flys/exports/LegendProcessor.java: + New (extracted from XYChartGenerator). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Extracted legend item aggregation to LegendProcessor. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Removed trailing whitespace. + +2012-06-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Minor polish for LegendItem-Aggregation. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Define and use static SPACE Shape. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java: + Completed inverse stubs. + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java: + Register the singletons instead of new objects. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java: + Link the functions to there inverses via getInverse(). + +2012-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Implemenation of the inverses of the fitting functions. Needed + for the AT export of the calculated curves. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: + Added abstract method getInverse() to get the inverse of the + function. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java: + Implements the getInverse() method. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/InvLog.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvExp.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/InvLinear.java: + Implements the inverses of the function above. Some are still + stubs. + +2012-06-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue663 ("step" curves for Q). + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java + (addStepPointsKmQ): New, add "step" points for series. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Use new StyledSeriesBuilder function. + +2012-06-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Fix LegendAggregation; prevent single aggregated legend item to + overflow by splitting it into many, but iconless legenditems. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Fixed typo in I18N key. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Finished I18N. + + * src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java: + Accept callback to label legend items. + + * src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: Added interface + LabelGenerator to create labels for entries. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added strings. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java: + Removed trailing whitespace. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java, + src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + Removed superfluous imports. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Uses I18N now. + + * src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java: + Added convenience constructor for creating date formatters with strings. + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Added variadic method format(). + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added strings. + +2012-06-25 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java: + New. Generator for longitudinal sections in fix analysis. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java: + New. Facets for longitudinal sections chart in fix analysis. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new facet types. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Add facets for new chart. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Fixed NPE. + + * doc/conf/artifacts/fixanalysis.xml: + Added facets to config. + + * doc/conf/themes.xml: + Added new themes. + + * doc/conf/conf.xml: + Added new chart generator. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-06-25 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Look for the attribut "outline" to render shape outlines in charts. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Add the "outline" attribute. + +2012-06-25 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Do not add entries ending with " " to legend. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Prevent that the plot becomes to small if only one point is drawn. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Added debug output about the concrete coeffs found by the fitting. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java: + Re-checked the partial deviations to the coeffs. Write the formulas + more human readable. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: If a label collides + with a other labels try to draw it on the other side of the point. + This results in more labeled points which is useful because you cannot zoom + in for details in the fixings km chart. + + * src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java: + Paint measured points blue and interpolated green. + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Set background color to white. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Interpolated and measured values where switched. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Label the points in diagram and show if they are interpolated or not. + + * src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java: + New. Extended XYSeriesCollection to cope with QWs + + * src/main/java/de/intevation/flys/utils/Formatter.java: Added formatters + to be fetched only over CallMeta. CallContext are not present in services. + + * src/main/java/de/intevation/flys/java2d/ShapeUtils.java: New. Some code + to handle Shapes. + + * src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: New. Shape + renderer. This is a simplified version of the shape renderer + from fixings analysis in desktop FLYS. + +2012-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Re-added accidentially removed code. + +2012-06-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: + Removed trailing whitespace. + +2012-06-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Removed TODOs about I18N + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added strings for fixing analysis. + +2012-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/KMIndex.java: + OpenJDK javac 1.6.0_24 seems to be more picky about + correct usage of generics. + +2012-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/add-i18n-numbers.py: New. Script to prefix + the values of property files with a small number to + make the keys identifiable even through the UI. + + Apply in the same manner as contrib/check-i18n-properties.py + +2012-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/messages_de.properties, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties: + Repaired inconsistencies. + +2012-06-24 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java, + src/main/java/de/intevation/flys/jfree/XYStyle.java: + Add debug logs. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: + Draw the W/Q function as StyledXYSeries. + +2012-06-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Re-enable legend entry aggregation, take the threshold from + settings. + +2012-06-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: + Parse and set legend aggregation value. + +2012-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java, + src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java: + Removed trailing whitespace. + +2012-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Added bug output when creating Q sector markers. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java: + Added toString() method. + +2012-06-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Set the aggregation threshold value. + +2012-06-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java, + src/main/java/de/intevation/flys/collections/OutputParser.java: + Cosmetics, doc. + +2012-06-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/WstWriter.java: + Cosmetics. + +2012-06-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Draw domain markers for borders of Q sectors. There is some kind of glitch + in in the Q sector classifaction code or the db data is strange. + + Because of the common code basis this affects the fixings calculations, too. :-( + +2012-06-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Calculate the standard deviation of the Q sector delta Ws, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java: + Store the standard deviation of the Q sector delta Ws, too. + Indexed 0..3; NaN means the std dev for this sector is not existing. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java: + added method getSectorBorder(int). With this method you can figure + the three discharge sector borders. Returns NaN if border is + not there. Usage: + + GaugeFinderFactory ggf = GaugeFinderFactory.getInstance(); + GaugeFinder gf = ggf.getGaugeFinder("Elbe"); + if (gf == null) { /* FAIL */ } + GaugeRange gr = gf.find(km); // km is the km where you are. + if (gr == null) { /* FAIL */ } + + double m0 = gr.getSectorBorder(0); // Draw as marker if not NaN + double m1 = gr.getSectorBorder(1); // Draw as marker if not NaN + double m2 = gr.getSectorBorder(2); // Draw as marker if not NaN + + Labels should be: + '(MNQ+MQ)/2' for m0 + '(MQ+MHQ)/2' for m1 + 'HQ5' for m2 + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java: + New. Cache access to per river gauge finders. This very useful + if you want to draw the discharge sectors of river at a given + km into a diagram. + + * doc/conf/cache.xml: Added cache 'gauge-finders'. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java: + Added find(double km) method to find GaugeRange by km. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Uses the instance of the GaugeFinderFactory to access the + gauge ranges. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Simplified code. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java: + New. Moved out of FixingsOverview. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Moved GaugeFinder into top level class. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java: + New. Moved out of FixingsOverview. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Moved GaugeRange into top level class. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Prevent some NPEs. + !!! This is not a fix for the real problem !!! + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Removed superfluous imports. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Range.java: + New. Moved out of FixingsOverview. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Moved Range into top level class. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java, + src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java: + Adjusted imports. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Fixed problem with select the wrong meta data (date, descriptions, etc.) + for a data column. + +2012-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + Fixed stupid i/j switch bug. + +2012-06-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Updated i18n. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n string for delta W(t) chart. + +2012-06-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Added attribution for single series styling. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Skip legend items for interpolated point series. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + Split analysis and reference points into two chart series. Added attribute + for interpolated points for different styling. + + * src/main/java/de/intevation/flys/jfree/Style.java: + Added getter for renderer. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: + Implemented getter for renderer. + +2012-06-21 Christian Lins <christian.lins@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Split fix_sector_average_wq in four facet types, one for each class (_0, _1, ..) + + * doc/conf/themes.xml: + Update themes for WQ curve + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Fix for small issue with sector average points + +2012-06-21 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Adapt doAverageSectorOut() to reflect changes in Facet. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + Added delta W(t) chart in fix analysis. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added facet types for deta W(t) chart. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Changed facet index to determine the sector index and the analysis period + index. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Calculate a facet index including the sector index and the analysis period + index. + Added new facet for delta W(t) chart. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java: + New. Facet to display the standard deviation in delta W(t) chart. + + * src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java: + New. Generator for the delta W(t) chart. + + * doc/conf/artifacts/fixanalysis.xml: + Updated facets in outputmodes. + + * doc/conf/conf.xml: + Added output generator to config. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + New methods to add domain and value axis markers to the plot. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + Added reference events to CSV export. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java: + Changed data type from QW[] to QWD[] to have delta Ws in reference events. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Moved function instantiation to alway have a valid function instance. + +2012-06-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Fixed binary search. + +2012-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Bring binarySearch with epsilon more to source of binarySearch of Collections. + Still not working properly. Why? + +2012-06-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Avoid problems with corrected Ws in cross-sections; hacky solution, + issue680. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (waterLineC): New, get corrected W. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + Create C-facet with other index. + +2012-06-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Cosmetics, doc. + +2012-06-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Cosmetics, doc. + +2012-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Now respects the selected events and reference period correctly. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + referenceStart and referenceEnd are now melted into referencePeriod. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Add a new filter IdsFilter which is more efficent to check than a + OrFilter with a list of IdFilters inside. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + Expose the new IdsFilter to the XML representation in form of + <columns cids="<list of whitespace separated ids"/> + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Fixed broken naming of chart curves. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Renamed facets for SQ + relation chart curves. + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Create a compound index value for SQOutlierFacets. This index is based + on the index of the result object (to get the correct data) and the + iteration of the outliers. This compound index is used to make + SQOutlierFacets unique to FLYSCollection's DESCRIBE document. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java: + Parse the index of the result object and the iteration number from index + property. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Added some more debug output. + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Create only SQ objects with values > 0. Otherwise JFreeChart will break + during chart creation (values for logarithmic axes have to be > 0). + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Adjusted the color of SQ Facets (lines and points) + as shown in examples. + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Create new Facets with proper i18n label. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for facet + names. + +2012-06-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorA.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorB.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorC.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorD.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorE.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorF.java: + New concrete chart generators. Each fraction of the SQ relation + calculation has its own generator now. This is because they all have + different chart titles and labels. + + * doc/conf/conf.xml: Let SQ relation charts use more concrete generators. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Implemented getDefaultXAxisLabel() getDefaultYAxisLabel(). + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for chart + titles and axes labels. + +2012-06-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue681 (wrong vertical lines in duration curve q-mainvalues on + second y-axis). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Fix vertical line if on second y-axis. + +2012-06-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java: + Restrict q-filter facet to the differences case. + +2012-06-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/waterlevel.xml: Add Q-facets to compatibility list. + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java: + Add Q-facets to filter facet list. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java, + src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Removed trailing whitespace. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: Directly + sample "our" Function objects instead of JFreeChart Function2Ds. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Removed JFreeChart Function2D wrapper and directly use our Function + objects. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Removed superfluous imports. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Calculate the standard deviation of the delta Ws of the referencen points, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Store the standard deviation of delta Ws of reference points into + a parameters column "std-dev". + +2012-06-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: New function to + sample a Function2D. This method is used, because JFreeChart's + DataUtilities.sampleFunction2D() returns an instance of XYSeries but we + need StyledXYSeries. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: Added a + method to retrieve parameter values for a list of parameter names. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Create a fake Parameters object for the SQ curve. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java: + Added getMinQ() and getMaxQ() to determine the Q range. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFunction.java: New + model class that stores a Function and a min and max Q value. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java: + Return a SQFunction instance based on the parameters and Q range of the + SQFractionResult. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: Use + JFreeUtil's new function sampleFunction2D to create a StyledXYSeries for + the SQ curve. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Store into QWs if they are interpolated. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + Stores boolean if the values are interpolated. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java: + Name derivative S'(Q). + +2012-06-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Add Q-Facets to compatibility list of dis-c. + +2012-06-19 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added theme mappings for sq relation fractions b - f. + +2012-06-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: Renamed + the former SQResult to SQFractionResult. This class is now used to store a + set of SQFractionResults for each SQ calculation. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java: + Former SQResult. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Create new fake SQFractionResults for fraction A, B and C (used for + testing). + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java: + Added the 'fractionIdx' property to get to know which fraction should be + represented. + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: Create + Facets for each SQResult and SQFractionResult. + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java: + New. S(Q) = a*Q^b + + * src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java: + Registered new function. + +2012-06-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java: + Implemented getData(). It returns the SQ[] of + SQResult.getMeasurements(). + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: Create + proper facet for sq measurements and corrected constructor call of + SQOutlierFacet. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Generalized doSQMeasurementsOut() and doSQOutliersOut() to one single + method doSQOut() which is able to handle SQ[] data. + +2012-06-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Changed the + default behavior: line labels are not visible if no config option is set! + +2012-06-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Load config of rest server and floodmap over + external entities, too. + + * doc/conf/floodmap.xml, doc/conf/rest-server.xml: New. + External config. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + The reference points are now wrapped in QWDs. This enables the + plotting of Delta W(t) data for the reference points. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + Added convenience constructor. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Adjusted. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java: + Cosmetics. + +2012-06-18 Christian Lins <christian.lins@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Remove fix_analysis_periods_wq from fix_wq_curve facet. + + * doc/conf/themes.xml: + Add fixing themes for other theme groups. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java: + Debug output added. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java: + Added vim line, made class public. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Using external system entities to configure databases. + !!! + !!! FROM NOW ON YOU CAN YOUR conf.xml FROM TRUNK. + !!! Adjust the database credentials via the *-db.xml files + !!! which are included. + !!! + + * doc/conf/artifact-db.xml: New. Configuration for the artifact database. + * doc/conf/seddb-db.xml: New. Configuration for the SedDB + * doc/conf/backend-db.xml: New. Configuration for the FLYS3 database. + * doc/conf/datacage-db.xml: Configuration for the datacage datacage. + +2012-06-18 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java: + Fixed constructor. + +2012-06-18 Christian Lins <christian.lins@intevation.de> + + * doc/conf/themes.xml: + Add themes for fixing facets. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java: + Use FixFacetUtils.getMaxQ() to retrieve max Q. + Interpolate km values instead of strict binary search. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java: + Added, contains static getMaxQ() method. + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Some issues fixed. + +2012-06-18 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Fixed broken color strings. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added new functions + that return colors for points. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: Added new + function that returns the color for points. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: Added new method to + apply the color of points (independent of the specified line color). + +2012-06-18 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added themes for SQ relation charts + ('sq_a_measurement', sq_a_outlier' and 'sq_a_curve'). + +2012-06-18 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java: + New. Abstract chart generator for fix analysis. This generator adds the + current km to the context. + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Generators now extend the FixCahrtGenerator. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java: + Get the current km from context. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Removed getter for current km. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/map/PrintMap.java, + src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java, + src/main/java/de/intevation/flys/artifacts/states/SQRelation.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeState.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java: + Removed repeated x.size() calls from for loops. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Removed superfluous imports. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java, + src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java, + src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java: + Added missing 'else's in if/else ladders. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java: + Fixed string comparision for identity. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/**/*.java: Added missing vim lines. + +2012-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Removed tabs. Set log level from INFO to DEBUG because this case + is much too common. + +2012-06-17 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Comments added. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + Logging output added. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java: + Max Q is now determined by parameter.interpolate(). + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java, + src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Use getCurrentKmFromRequest() in output generation. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Typo in method description. + +2012-06-15 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java: + The getData() method now takes a km parameter to get the data at a specific + km. + +2012-06-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQ.java: New model to + store values for S/Q. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: New + model class that should be used to store calculation results of SQ + relation. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java: + Create a fake SQResult. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java: + Set missing required properties, so that this facet will be able to + re-calculate results again if the results are not in cache. + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Create correct number of facets for parameter A for outliers Facet. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: + Create a JFreeChart XYSeries from SQResult's outliers Facet. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added a + method to create X axes. The SQRelationGenerator overrides this method, + because it requires a logarithmic axis. + +2012-06-15 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Added getter for current km. + +2012-06-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new functions to determine if a Facet is a SQ curve, measurement or + outlier independend of their parameter. + + * src/main/java/de/intevation/flys/exports/sq/SQRelationInfoGenerator.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java, + src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java: + Stubs for chart and export generators. + + * doc/conf/conf.xml: Registered new output-generators for SQ relation + charts and exports. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for CSV + export of SQ relations. + +2012-06-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/**/*.java: Removed trailing whitespace. + +2012-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Added out commented block for SedDB configuration. + +2012-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + Some code cleanup. + +2012-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Added more debug output. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + Interpolate the coeffs for the function to be drawn. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Made code more robust for none existing data. + +2012-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new Facets for MINFO SQ relation calculation. + + * doc/conf/artifacts/minfo.xml: Added output for chart and data export for + sq relation calculation. Registered new facets. + + * src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java: + Stubs for calculation and Facets used for SQ relation calculation. + + * src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + Override computeAdvance() and implemented a stub for calculation and + Facet creation. + +2012-06-11 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Changed filter string to 'Messstelle'. + +2012-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Fetch only cross section tracks that have a name 'qps' set for WSPLGEN + calculation. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Use binary search again. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java: + Removed superfluous import. + +2012-06-13 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Workaround for IndexOutOfBoundsException. + + * src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java: + Output generator for fixing derived curve. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + Use binary search with epsilon again. + +2012-06-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Added more debug/warn log statements. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: Do + not add empty objects into the calculation result. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Take care on empty QWD objects. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java: + Max Q is store in column "max_q" in Parameters now. So function can be plotted + bewtween calculated kms, too. + For function sampling use something like this.: + + double [] maxQ = parameters.interpolate("km", 42.3", new String [] { "max_q" }); + double maxSampleQ = 10000d; + + if (maxQ != null) { + maxSampleQ = Math.min(2000d, Math.abs(maxQ[0])); + maxSampleQ += 0.05*maxSampleQ; + } + +2012-06-13 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Add missing imports and correct coding issues. + +2012-06-12 Christian Lins <christian.lins@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Use KMIndex.search() (with epsilon) instead of KMIndex.binarySearch(). + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Move marker generation to XYChartGenerator. + +2012-06-12 Christian Lins <christian.lins@intevation.de> + + * doc/conf/conf.xml: + Add fix_wq_curve output generator. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java: + Add additional null-checks to prevent NullPointerExceptions when accessing empty + facets. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java: + getMaxQ() now returns constant '1000' until it is properly fixed. + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Code for generating charts more or less complete but untested due to bugs in facets. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added method double [] interpolate(keyName, key, columnNames). + This construct is better suited for the extraction of + coefficients for building functions. In pseudo code: + + fitting.Function function = + FunctionFactory.getInstance().getFunction("log"); + + double km = 42.35; + + double [] coeffs = parameters.interpolate( + "km", km, function.getParamterNames()); + + math.Function f = function.instantiate(coeffs); + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java: + Removed superfluous imports. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added interpolate methods that return an array of linear interpolated + values for a given key. Say you have a column named "km" you can call + 'values = parameters.interpolate("km", 12)' to fetch a set + of proportional interpolated parameters even if there are only + "km": 10 and "km": 15 in the data structure. Returns null if out of bounds. + +2012-06-11 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/minfo.xml: + Added states and transitions for S-Q-relation. + + * src/main/java/de/intevation/flys/artifacts/states/PeriodsSelect.java, + src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java, + src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: + New. States for multiple periods input, outliers input and final + S-Q-relation. + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Added name filter for locations. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for states. + +2012-06-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java: + Fixed broken logger class. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Re-establish old indentation. + +2012-06-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + (doWOut): Interpolate values from WKms. + +2012-06-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java: + Enable caching. + +2012-06-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Simplified choice of gauges for discharge c. + + * src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java: + Create better name for facets, minor refactoring, polishing. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-06-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java, + src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java: + Cosmetics, docs + +2012-06-07 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Use i18n strings. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-06-07 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Changed facet description. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java, + src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Cosmetics, doc. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java: + Fix issues, import river, documentation, more debug. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java: + Hard-code state id, instruct computation to result in facets. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Doc. + +2012-06-06 Raimund Renkert <raimund.renkert@intevation.de> + + Added facet for derivate curve and fixed facet names. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java: + New. Facet for derivate curve. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java: + Added name for facet to constructor. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Add one facet for each output using a different name. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added facet names. + + * doc/conf/artifacts/fixanalysis.xml: + Changed facet names. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java: + Trivial doc. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage.txt: More documentation of datacage conf. + +2012-06-06 Raimund Renkert <raimund.renkert@intevation.de> + + Added new facet for analysis periods and updated facet names. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java: + New. Facet for analysis periods. Returns the date ranges for the analysis + periods. + + * doc/conf/artifacts/fixanalysis.xml, + src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new facet and updated facet names. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java: + Updated facet names. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Minor doc. + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage.txt: More documentation of datacage conf. + +2012-06-06 Raimund Renkert <raimund.renkert@intevation.de> + + Implemented facets and splitted up the event facet. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixEventsFacet.java: + Removed. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java: + New. Facets for events. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java: + Implemented getData(). + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Add new event facets. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java: + Fixed return value. + +2012-06-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/Function2DAdapter.java: + New. Adapter class to brigde de.intevation.flys.artifacts.math.Function + to org.jfree.data.function.Function2D. + + Function2D objects can be used by org.jfree.data.general.DatasetUtilities + to sample functions into XYDatasets. + See DatasetUtilities.sampleFunction2D() + +2012-06-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/datacage.txt: New file that will contain datacage configuration + documentation. + +2012-06-06 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Fixed outputmodes. + +2012-06-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Local variable shadowed instance variable. + +2012-06-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Fixed index problem with name of chi^2. + +2012-06-06 Raimund Renkert <raimund.renkert@intevation.de> + + Added facets for fix analysis. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixEventsFacet.java: + New. Facets for W/Q-Chart in fix analysis. FixAvSectorFacet is implemented, + the others are just stubs. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Add facets to artifact after calculation. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Added method to get the current km for charts. The km is used for + synchronous navigation in fix analysis charts. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new facet types. + + * doc/conf/artifacts/fixanalysis.xml: + Added facets to config. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added some binary search methods. TODO: Sort by column. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + Use new data structures for export. + + * src/main/java/de/intevation/flys/utils/KMIndex.java: + Implements java.lang.Iterable now. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWT.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java: + Removed. Obsolete. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Removed superfluous import. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Prevent duplicates in analysis periods. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java: + Added equals. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/EpsilonComparator.java: + Removed. Obsolete now. + +2012-06-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: + Improved collision detection. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Avoid collisions of line labels, documentation. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Use JFreeUtil. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java: + New, ChartEntity class for Line labels. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + Store the QWs that are actually used in the fitting as referenced. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Store the referenced QWs for each km. TODO: Use same index structure. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Store the referenced QWs, too. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResults.java: + Removed. Obsolete. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriodsKM.java: + Removed. Not needed any longer. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Store the AnalysisPeriod per km into FixResult. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Uses KMIndex<AnalysisPeriod []> instead of DeltaWTsKM now. + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + Commented out old code. + TODO: Rewrite exporter to use AnalysisPeriods. + +2012-06-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Override + endOfLife() to remove files and directories produced for WMS output. + +2012-06-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: + New jfreechart-related utility class. + +2012-06-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/Formatter.java: + (getMeterFormat): New. + Doc. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + i18n and formatting for line labels. + +2012-06-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Added better doc and TODO. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Now uses the KMIndex for outliers. + TODO: Use KMIndex for DeltaWTs, too. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/KMIndex.java: New. + Serializable index structure to find objects by there km. + TODO: Use in fixings analysis. + +2012-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/EpsilonComparator.java: + Fixed sign problem in comparison. + +2012-06-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Implemented outlier checks in fixings analysis. Expected to be + still broken, but the code is in the right place now and has the + right structure. + + * src/main/java/de/intevation/flys/artifacts/math/Outlier.java: + Fixed endless loop. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added further set methods for indexed access. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: + New. Out factored fitting code from FixCalculation. Checks for outliers, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Moved fitting code out to separate class. Streamlined code a bit. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + Store the outliers from fitting in separate data structure, too. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java: New. + Base class for delta W/t data. Used as storage for outliers. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + Is a sub class of QW now. + +2012-06-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Store Chi^2 of fitting into result, too. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Added indexed set method. + +2012-05-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: + Added inner class Derivative representing the first derivative of the + function. Can be instantiated with a given set of parameters. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java, + src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java: + Added the derivatives of all fitting functions. + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Calculate the Delta W/ts + + the average Delta W/ts per Q sector per analysis period. + !!! Very complicated stuff !!! + TODO: + - Store results into the new data structures AnalysisPeriod and + AnalysisPeriods. + - Remove the old DeltaWTsKM and DeltaWT. + - Adjust the facets and the export. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + Added convinience constructor. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Added sector filter. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + Expose the new sector filter to the fixing overview service. Syntax: + <sector value="<value>"/> + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/DateAverager.java: + New. Averages a list of dates preventing overflows. + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Added a km filter to find columns which touches a given km. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + Expose the new km filter to the fixing overview service. Syntax: + <position km="<value>"/> + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Better persistence model for delta w/t calculations. Supports + storage of Q sector averages, too. TODO: Use the new model. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java: + New. Will be used as a replacement for DeltaWT. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java: + New. Will be used as a replacement for DeltaWTsKM.KM. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriodsKM.java: + New. List<AnalysisPeriodsKM> Will be used as a replacement for DeltaWTsKM. + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Use DateRange objects now. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java: New. + Model for date ranges. To be used in re-factored persistance model. + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Added method to find the Q sector of fixing column for a given km. + Useful to classify fixing events at certain kms. + +2012-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Fixed access to analysis periods. + +2012-05-30 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Changed data fields to a single string data field. The data contains a + string of semi-colon separated 'long' value pairs. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Process the new data. + +2012-05-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java: + trivial doc. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Removed disturbing comment. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java + (SimpleAxis): Add ommitted Y_AXIS2 to enum. + +2012-05-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + solve issue417: duration curve annotations as line to curve. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java + (createStickyLineAnnotation): New. + Resolved todos, use the line style. + +2012-05-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Doc, TODOs added. + +2012-05-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Consider theme setting before drawing line to curve. + +2012-05-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Donate own theme for mainvalues. + +2012-05-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Fit from Q to W not from W to Q! + Delta w/t's are now in cm. + Slimmed down fitting error report. + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + Changed default column header of delta W to cm. + +2012-05-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Made Delta W/t calculation work. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: + Added toString() method. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java: + Fixed problem accessing Ws. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Fixed silly 'name.equals(name)' bug. This mainly prevented delta W/t + computation from working. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java: + More deug code. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + More debug code. Simplified access to data a bit. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Allow CSV exporter to throw IOExceptions. + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + More debug output. Flush CSV after writing. + +2012-05-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Units of step is in meter and not km. Added more debug output. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Stupidly forgot to add facet to return the delta w/t as CSV. + +2012-05-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java: + There was a cast to WINFOArtifact where a cast to FLYSArtifact + is sufficient. This prevented generating error reports that + does not inherit from WINFOArtifact like FixationArtifact. + +2012-05-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml, + doc/conf/conf.xml: Added CSV and error report generator/facets. + +2012-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java: + CrossSectionFactory.isNewest() will return true if the CrossSection is + the only CrossSection found in the database. No IndexOutOfBounds is + thrown. + +2012-05-27 Ingo Weinzierl <ingo@intevation.de> + + * Tagged module as '2.7'. + +2012-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Don't break chart creation if no hyks are existing. + +2012-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java, + src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java, + src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java: + Removed superfluous imports. + +2012-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java: + Added getters to access the inner data structures. + + * src/main/java/de/intevation/flys/utils/Formatter.java: Added formatting + support for delta w/t exports of fix analysis. + + * src/main/java/de/intevation/flys/exports/DeltaWtExporter.java: + New. CSV exporter for delta w/ts of fix analysis. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Reordered imports. + +2012-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FitResult.java: + Removed. Obsolete. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java: + New. Stores the result of the fixing analysis. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Return the right structure (FixResult) from the calculation. + +2012-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Fixed stupid index bug. + +2012-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + Call the computing. + +2012-05-25 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Use the correct Artifacts for wms fixpoints and + floodmaps (they were interchanged). + +2012-05-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResults.java: + New. Stores all results of a fixing analysis. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java: + New. Km indexed container for Delta W/t diagrams. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Create FixResults and DeltaWTsKM now to store the results. + +2012-05-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: + Replaced another silly "@attribute" XPATH with direct getAttribute() + call. + +2012-05-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Draw line of mainvalues to duration curve hit point to ground. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Also work for q-value case on second y-axis, refactored. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java: + Doc and fix.Doc and fix. + +2012-05-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Also draw lines to curve from q-mainvalues in dur. curve + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java: + In analogy to the W-case, calculate where line from main value hits + a wqday-curve from DurationCurve. + +2012-05-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Draw line of w-mainvalue to duration curve hit point to ground. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + If StickyAxisAnnotation has a hit point set, also add line annotation + from the crossing point to the x-axis. + +2012-05-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Draw line of w-mainvalue to duration curve, baby version. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Added field "hitPoint", when a line to a point should be drawn + - leveraging this annotation into the second dimension. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java: + Calculate where mainvalue hits a duration curve. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + If StickyAxisAnnotation has a hit point set, add line annotation + to hit (the duration) curve. + +2012-05-25 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added a warning to not use virtual themes for facets. + +2012-05-25 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added concrete themes for maps. + +2012-05-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Moved parameter of addAnnotations out, renamed to addVisibleAnnotation. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Adjusted. + +2012-05-25 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added concrete themes for areas. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Load mainvalues in reference curves. + + * doc/conf/artifacts/winfo.xml: Add mainvalues to compatibility list + of reference curves; fix typo. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Render mainvalues as annotations. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Render static wkms data. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Cosmetic. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java, + src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + (flipStickyAxis): Allow easy change of sticky axes. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (getWaterlevelData): Exception for discharge case. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java + (getLocations): Exception for discharge case. + +2012-05-24 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 667. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Added data to jfreechart data source. + +2012-05-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/services/ThemeListingService.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/HYKArtifact.java, + src/main/java/de/intevation/flys/artifacts/AreaArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/themes/ThemeGroup.java: Removed + needless imports. + +2012-05-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Reproject + geometries into the coordinate reference system defined in the + configuration. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Include other "thematic" heights for + reference curve relative points dc conf. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java: + Added TODO. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/relativepoint.xml, + doc/conf/conf.xml: Remove relativepoint artifact remainders, so far + all cases are covered by facet. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Handle reference curve case, slightly refactored. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Handle points in doOut. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Expose data via blackboard. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Serve fixations + with relative points for reference curves. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (getReferenceStartKm, getReferenceEndKms): Made public. + +2012-05-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Add relative point to compatibility + list of reference curve out. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Remove second facet from + StaticWKmsArtifact from compatibility list of duration curves. + + * doc/conf/themes.xml: Add basic theme for relativepoint. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Serve floodprotections and heightmarks + with relative points for duration curves. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Handle relative points in doOut. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Serve fixations with relative points + for duration curves. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java: + Use superclass static field and method. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java: + Handle duration curve case. Do a linear interpolation of the day. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java: + Be a DataProvider, provide the duration curve and its km. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + (getWAtKmLin): Linear interpolating version of getWAtKm. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java: + Add (dummy-) implementation of a relative point facet. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Use superclass infrastructure. Spawn RelativePointFacet. + + * doc/conf/winfo.xml: Add relativepoint facet to compatibility list + of duration curve out. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Add RELATIVE_POINT Facet Type. + +2012-05-23 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: + Allow instantiation of a function with concrete parameters. + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + Enable indexed access to parameter names. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FitResult.java: + New. Bundles the results of the fitting. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWT.java: + New. Stores results of Delta W/t calcs. + + * src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java: + Calculate Delta W/t s, too. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Make component filters ('and', 'or') more easy to construct. + +2012-05-23 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java: + Improved startup performance. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java + (getDatacageIDValue): New, extracted from various duplicates. + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java, + src/main/java/de/intevation/flys/artifacts/AreaArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: + Use getDatacageIDValue() from superclass or static context. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java: + Define XPath to access "id" value of element coming from datacage-document. + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java, + src/main/java/de/intevation/flys/artifacts/AreaArtifact.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: + Use xpath defined in superclass. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + Whitespace-Cosmetics. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/relativepoint.xml: New artifact-state-config for upcoming + artifact. + + * doc/conf/conf.xml: Register artifact factory and artifact for + upcoming artifact. + +2012-05-23 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/themes/ThemeGroup.java: + New. A theme group takes a set of themes configured in the themes.xml. + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: + Read the theme groups configured in the themes.xml. + Improved reading the xml file. Thanks to Sascha for the patch. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Get a theme using the new parameter themegroup. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Create theme groups while configuring themes. + + * src/main/java/de/intevation/flys/artifacts/services/ThemeListingService.java: + New. This service returns a list with all configured theme groups, each + containing exactly one theme filtered by name. + The theme name has to be provided as parameter. + + * doc/conf/conf.xml: + Added new service to config. + + * doc/conf/themes.xml: + Introduced theme groups and added new group. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Repair CS-DC-Conf, allow loading + waterlevels, add fixations and heightmarks. + +2012-05-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Cosmetics. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow loading of fixations in cross-sections. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java: + More debugging of discharge curve issue. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java + (getDischargeCurveData): Moved to more specific class. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java: + Cosmetics, be louder in miscondition. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow loading of fixations and thmatic + heights in longitudinal sections, make discharge-curve-misbehavior + testable with trunk. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Render discharge outs (was own out once). + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Allow cross-section stuff in + dischargelongitudinal state. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + Add CrossSectionWaterLineFacets, will trigger the cross section output. + +2012-05-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FixationArtifact.java: + Added vim line. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Removed empty line. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Removed invalid/not helpful comments. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java + (outputExists): Doc. + +2012-05-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java: + Adjusted ui providers to make parameter names unique in client. + +2012-05-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Fixed short evaluation problem. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + Added more debuf output. + +2012-05-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: + New. Access the state data of fixings artifacts. + +2012-05-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: Make "start" and "end" parameters + unique in fixings artifact states. + +2012-05-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/winfo.xml: Extend compatibility lists. + + * doc/conf/conf.xml: Add gaugedischarge factory and artifact. + + * src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java, + src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java: + New, State, Facet and Artifact to access discharge curves of gauges. + + * doc/conf/gaugedischarge.xml: New trivial state model for gaugedis. + +2012-05-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow loading of prev. reference curves. + +2012-05-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: (yet unused) sceleton for ref-curve dc conf. + +2012-05-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for fix analysis. + +2012-05-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/fixation/EventSelect.java: + Implemented static data for state. + + * doc/conf/artifacts/fixanalysis.xml: + Changed transition in 'volmer' states. + + +2012-05-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java: + Include km in names of duration curve facets. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Adjusted i18n for + duration curve facet names (now include km). + +2012-05-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow loading of previous duration curves and + fixations in duration curves. + +2012-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java: + Take the current km range into account in getOptions(). + +2012-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java, + doc/conf/artifacts/minfo.xml: Adapted facets for middle bed height. We + now distinguish between epochs and singles. + + * doc/conf/conf.xml: Registered new output generator for middle bed height. + + * doc/conf/themes.xml: Added new themes for middle bed height epoch and + single curves. + + * src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java: + Take the km range into account. + + * src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java: + Create facets for single and epochs. + + * src/main/java/de/intevation/flys/exports/MiddleBedHeightInfoGenerator.java, + * src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java: + Chart and info generator for middle bed height charts. + +2012-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java: + Added new methods that create names for singles and epochs. + + * src/main/java/de/intevation/flys/utils/Formatter.java: Added number + formatters used to export middle bed heights values. + + * src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java: + New exporter for middle bed heights values. + + * doc/conf/conf.xml: Registered new output generator for middle bed height + exports. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New i18n strings for middle + bed height facets and csv export. + +2012-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java: + New model class for storing data for middle bed height exports (chart, + data exports). + + * src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java: + New Calculation that generates new MiddleBedHeightData. + + * src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightFacet.java: + New Facet which is used for middle bed height charts. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new facet type for middle bed height curves. + + * src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java: + Calculate middle bed height data using MiddleBedHeightCalculation and + create new facets for charts and csv export. + + * src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Added new + methods that return the IDs of selected single bed heights and epoch bed + heights. + +2012-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java: + Implemented getOptions() and getLabelFor(). + +2012-05-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Stabilized legend item aggregation. + +2012-05-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Extensive - although mostly trivial - doc adds. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Added states and transitions for MINFO + middle bed height calculation. + + * src/main/java/de/intevation/flys/artifacts/states/MultiStringArrayState.java: + New. Nearly a copy of MultiIntArrayState but uses String values. + + * src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java: + New subclass of MultiStringArrayState. It will be used for bed heights + selection. We need to do handle the values as string, because singles + and epochs are mixed, so the DB ID is not enough as parameter value. + + * src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java: + New. This state will trigger the calculation for middle bed height in + MINFO module. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java: + Do not add a <art:choices> element to the dynamic DESCRIBE but add the + <art:item> directly to <art:select> which allows using default mechanism + in FLYS client. + +2012-05-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Replaced event name by its description, which combines the + description of the fixing (= WST file description) and the name + of the column. + + * contrib/fixoverview2html.xsl: Adjusted. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Added a chart output and relevant facets to + flow velocity state. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new facet types for mainchannel, totalchannel and tau of flow velocity + calculation. + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityFacet.java: + New Facet that returns FlowVelocityData in getData(). + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityData.java: + Added new methods that return xy points for mainchannel, totalchannel and + tau. + + * src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java: + Create new mainchannel, totalchannel and tau Facets for each + FlowVelocityData instance retrieved by FlowVelocityCalculation. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Commented + legend aggregation out. + + * src/main/java/de/intevation/flys/exports/FlowVelocityInfoGenerator.java, + src/main/java/de/intevation/flys/exports/FlowVelocityGenerator.java: New + chart generator for flow velocity data and its info generator. + + * doc/conf/conf.xml: Registered the chart and chart info generator for flow + velocity data. + + * doc/conf/themes.xml: Added new themes for mainchannel, totalchannel and + tau of flow velocity calculation. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for flow + velocity facets. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java: + Add a 'label' attribute to each <data> element in the static DESCRIBE. + In addition to that, the <data> element created in this class can have + multiple <item> elements which consist of a 'value' and a 'label' + attribute. This 'label' attribute is taken from getLabelFor() which is + abstract and needs to be implemented by subclasses. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeState.java: + Implemented the abstract method getLabelFor(). + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: New i18n strings for MINFO + parameter names. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New i18n strings for MINFO + states. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/FlowVelocityExporter.java: + Append the name of a location for the km row which is provided by + FLYSUtils.getLocationDescription(km); + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for flow + velocity CSV export headers. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Added new state and csv export for MINFO flow + velocity calculation. + + * doc/conf/conf.xml: Registered a new CSV exporter for flow velocity + values. + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java: + New calculation for MINFO flow velocity. Actually, this is no + calculation but a bundling of data. + + * src/main/java/de/intevation/flys/artifacts/model/FlowVelocityData.java: + New model class that is used to store flow velocity relevant data. + + * src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java: + New state that triggers the FlowVelocityCalculation and creates new + facets. Currently, only a CSV Facet is created. + + * src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Added + methods to retrieve the IDs of main channels and total channels for the + flow velocity calculation. + + * src/main/java/de/intevation/flys/utils/Formatter.java: New formatters + that are used in CSV exporter for flow velocity. + + * src/main/java/de/intevation/flys/exports/FlowVelocityExporter.java: New + concrete subclasses of AbstractExporter that currently implements the + path to export FlowVelocityData as CSV. + +2012-05-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Removed getDataAsDouble() which is now implemented in FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Implemented getDataAsDouble(). This method will return a Double based on + a given parameter name. + +2012-05-15 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Changed data type for state 'eventselect'. + +2012-05-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java, + src/main/java/de/intevation/flys/artifacts/FixationArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java, + src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java, + src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Removed superfluous imports. + +2012-05-15 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Adjusted state data fields. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java: + Implemented states. + +2012-05-15 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: + Fixed constructor. Descriptions are now available. + +2012-05-15 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: Added new transistions and states for + MINFO flow velocity calculation. + + * src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java: + New abstract states that might be used to append a list of available + integer values to the DESCRIBE document. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeState.java: + Concrete subclass of MultiIntArrayState which implements the abstract + method getOptions(). + +2012-05-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Parameters.java: + New. Model for storing fitting results in cache. + +2012-05-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java: + Removed the computeFeed() method that created Facets for discharge + curves to make this state ready to use in MINFO calculations. + +2012-05-14 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/minfo.xml: New Artifact configuration for module + MINFO. + + * src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: New + Artifact for module INFO. + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelectMinfo.java: + New. The state is used for choosing the calculation in module MINFO. + + * doc/conf/conf.xml: Registered the MINFO Artifact. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New strings for states and + calculations. + +2012-05-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Removed unused code. + +2012-05-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Doc. + +2012-05-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow duration_curve.q loading via datacage. + +2012-05-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Allow hyk loading also when in non- + recommendation mode. + +2012-05-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved middle height calculations for waterlevels. + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java + (area): Improved or even corrected area calculation. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Corrected middle height calculated, have a very verbose label for + the time being. + +2012-05-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Somewhat improve area calculation during line computation. + Still faulty. + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java + (fillWater): Piecewise calculate area in more cases. + +2012-05-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Tackle water-through-mountain issue that exists since r4099. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java + (addPoints): Add parameter that decides whether or not to skip NaNs. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Set new parameter to StyledSeriesBuilder.addPoints calls. + For waterlines it is important that NaNs stay included! + +2012-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java: + New Artifact for storing geometries for gauges. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + a new facet type for WMSGaugeLocationArtifact 'floodmap.gaugelocation'. + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/map.xml: Added 'floodmap.gaugelocation' facet to the + list of valid facets for map and floodmap output. + + * doc/conf/conf.xml: Added a factory for creating + WMSGaugeLocationArtifacts. + + * doc/conf/themes.xml: Added a theme for 'floodmap.gaugelocation' facets. + + * doc/conf/meta-data.xml: Added a datacage section for gauge locations to + the floodmap and map section. + +2012-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new facet types 'floodmap.hydr_boundaries' and + 'floodmap.hydr_boundaries_poly' + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/map.xml: Registered 'floodmap.hydr_boundaries' and + 'floodmap.hydr_boundaries_poly' for floodmap and map output types. + + * doc/conf/conf.xml: + + * doc/conf/themes.xml: Added themes for 'floodmap.hydr_boundaries' and + 'floodmap.hydr_boundaries_poly'. + + * doc/conf/meta-data.xml: Improved datacage configuration specific to + floodmaps and maps. + + * src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java: + New artifacts to save information about hydrological boundaries. + + * src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java: + Moved the methods getRiverId() and getTitle() into WMSDBArtifact. + +2012-05-10 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/wsplgen_layer.vm, + doc/conf/mapserver/shapefile_layer.vm: Added a 'PROJECTION' section. + +2012-05-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Minor refactoring, doc. + +2012-05-10 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/layer.vm: Added a 'PROJECTION' section. + +2012-05-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Minimal doc, TODO. + +2012-05-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue620: synchron navigation at impossible kms. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java + (searchCrossSectionLine): Do not return a CrossSectionLine if there + is none found within 1km. + +2012-05-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Minimal cosmetics. + +2012-05-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Preparations for fix issue620: Synchron navigation on non-existing km. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java + (getData): Return empty lines if no cross section found. + +2012-05-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Display mittlere hoehe (which is not yet calculated). + + * doc/conf/themes.xml: Added theme prop to display middlere hoehe or not. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + (parseShowMiddleHeight): New, parse the new theme prop. + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + (fillWater, ListWithArea): Return new type wich also contains area. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Respect new theme prop and adjust label if set. + +2012-05-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Beginning of calculation of Mittlere Hoehe: area calculation. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Adjusted to LineData constructor. + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java + (area): New, calculate area of a polygon. + Added todos where area calculation code paths are missing. + +2012-05-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Moved the hws layers out to an own node. + + * src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Moved the + 'name' property from WMSCatchmentArtifact to WMSDBArtifact. + + * src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java: Create + more specific filter and extent that takes the 'name' into account. + +2012-05-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Moved the catchments out to an own node. + + * src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java: + Parse the name of required catchments fetch name specific catchments + only. + +2012-05-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/map.xml: Added the 'floodmap.floodmaps' facet to the + list of valid facets of the 'map' output. + + * doc/conf/themes.xml: Renamed the 'Line' theme used for floodmaps to + 'FloodmapLines'. + +2012-05-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/db_layer.vm: Added a PROJECTION section which is + filled by the LayerInfo object. + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Added + a 'srid' property. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Set the + 'srid' property of all LayerInfo objects. + +2012-05-07 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/fixanalysis.xml: + Changed state data and added new state. + + * src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/EventSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java: + Modified states and added new state for concrete event selection. + +2012-05-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes: Add text-bg properties to Area style. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java + (TextStyle.apply): Apply text bg theme-properties to renderer. + + * src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java: + Cosmetics. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Added field to store labels background color, calculate arithmetic + middles of polygons, to put label there (improves situation slightly). + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java + (parseShowArea): parse show area field of theme. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java + (TextStyle.apply): Be applicable to StableXYDifferenceRenderers. + + * src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java: + Apply setting from theme to renderer. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Simplified area calculation (always calculate). Added getters and + setters for text for label style, respect most of that. + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes: Let Area style not inherit from colorlines (as labels + work slightly different. Enable showarea property. Comment dupe Lines. + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java + (doArea): Add Lines.LineData datatype to areable data types. + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Add two new options for waterlevel label in cs. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Parse new theme properties. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Adjust label according to chosen properties. + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java + (parseShowLineLabelBG): parse show line label bg field of theme. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Respect show line label bg setting of theme. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: + Apply setting from theme to renderer. + +2012-05-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added a 'helpText' field to each state. + The 'helpText' field represents in this case a message in the i18n + resources which should be a link to a online help page. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Append the 'helpText' to the DESCRIBE document. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added links to help text in + the FLYS wiki. + +2012-05-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use the colors specified in theme document for linelabel. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + New methods to find colors specified for linelabels. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Store and use background and foreground color for linelabels. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: + Communicate colors of linelabels to renderer. + +2012-05-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Actually use the font specified in theme document for linelabel. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Fixed paths for linelabel-related fields in theme doc. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Set font for linelabel. + +2012-05-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: No default background show for linelabels. + +2012-05-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java: + Cosmetic, added annotation. + +2012-05-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Parse font for linelabels, do not use it yet. + + * doc/conf/themes.xml: Add more theme properties related to linelabels. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java + (parseTextSize, parseLineLabelSize): New and slightly refactored. + (parseLineLabelFont): New. + (parseTextStyle, parseLineLabelStyle): New and slightly refactored. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java + (setLineLabelFont, getLineLabelFont): New, accessors to + linelabelfont field. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java + (applyLineLabelFont): New. + +2012-05-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Make it compile again after signature change in backend. + +2012-04-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Doc. + +2012-04-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Added local class LineData and return it to also include + Length of lines. + + * src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java: + Changed signature of interfaces getWaterLines. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + (getWaterLines): adjusted signature. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Adjusted to return type of Lines.createWaterLines. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Include length in label (stub). + + * src/main/java/de/intevation/flys/jfree/HasLabel.java: + New interface. + + * src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: + Implement new HasLabel interface. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Take into account that StyledXYSeries are HasLabel. + +2012-04-26 Raimund Renkert <raimund.renkert@intevation.de> + + Initial transition configuration and artifact/state stubs for fixation + analysis. + + * doc/conf/artifacts/fixanalysis.xml: + New. Initial transition configuration. + + * doc/conf/conf.xml: + Added artifact and factory entry to config. + + * src/main/java/de/intevation/flys/artifacts/FixationArtifact.java: + New. Stub with initial implementation. + + * src/main/java/de/intevation/flys/artifacts/states/fixation, + src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java, + src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java: + New. Stubs for fixation states. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings. + +2012-04-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Add method to calculate length of water lines. + +2012-04-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Most of issue454: Label waterlevels. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java + (drawSecondaryPass): Use correct label for lines. + +2012-04-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java + (showSeriesMinimunX, showLineLabel): Renamed field. + (isShowLineLabel, setShowLineLabel): Added getters and setters for + showLineLabel field. + (drawSecondaryPass): Respect showLineLabel field, draw static text + as placeholder for real label (stub). + + * doc/conf/themes.xml: Define theme prop 'showlinelabel' for Lines. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Parse theme + theme prop. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: Apply showline + theme prop. + +2012-04-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Cosmetics, doc. + +2012-04-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Outlier.java: + Gah! Checked in out dated version. + + * src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java, + src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java: + Removed superfluous imports. + +2012-04-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/Outlier.java: + New. Simple Grubb's outlier test. Needs testing. ;-) + +2012-04-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java + (isMinimumX): Implemented minimum finding for x in analogy to the ones for + y values. Stub to label dataset curves in plot. + +2012-04-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Cosmetics, added doc, TODO and an OPTIMIZE. + +2012-04-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java: + Make it cross platform. + +2012-04-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java: + Make it compilable. + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 657. + + * src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java: + New. Service to upload a file as base64 string embedded in xml structure. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Extract shape files from zip archive and move them to artifact directory. + Add the user shapefile as parameter for wsplgen calculation. + + * src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java: + Remove the artifact directory on step back. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java: + Create layer to display the uploaded shapefile. + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: + Create a facet to output the user defined layer. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added type for user shape file. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: + Resized array for '-lin' parameter. + + * doc/conf/artifacts/winfo.xml: + Added facet to diplay user defined shapefile. + + * doc/conf/conf.xml: + Added file upload service. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n string. + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 560. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENLayerFacet.java: + New. Facet for WSPLGEN layers. + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: + Create a new WSPLGEN facet when creating uesk layers. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java: + Use WSPLGENLayerFacet to create uesk layer. + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Switch back to false as return value in isQueryable(). + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 560. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: + Generate WSPLGEN-Layer with its own template and set the layertitle to + an i18n string. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: + Call createUeskLayer with a CallContext. + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Set queryable to true. + + * doc/conf/mapserver/wsplgen_layer.vm: + New. Template for WSPLGEN-Layer. + +2012-04-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Removed superfluous imports. + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added mapping for manual points in historical discharge chart. + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Fixed duplicated legend entry for manual points. + +2012-04-18 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 494. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Create manual points with text annotations in time charts. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Add manual points to the chart. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added historical discharge to chart types. + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/manualpoints.xml: + Added manual points facet to output modes. + +2012-04-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/fixoverview2html.xsl: Render optional check boxes. + Use different font. TODO: Move to client, + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Ignore hours and seconds. + +2012-04-13 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 528, 637 + + * src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java: + Added fields for new columns. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Added columns for 'W at gauge' and fixed column header. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added filenames for new pdf export templates. + +2012-04-13 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/jasper/reference_gauge_end.jasper, + doc/conf/jasper/reference_gauge.jasper, + doc/conf/jasper/reference_gauge_start_end.jasper: + Small fixes in pdf templates. + +2012-04-12 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 528, 637. + + * doc/conf/jasper/reference_gauge.jasper, + doc/conf/jasper/reference_en_gauge.jasper: + Modified templates. + + * doc/conf/jasper/reference_gauge_end.jasper, + doc/conf/jasper/reference_gauge_start_end.jasper, + doc/conf/jasper/reference_en_gauge_end.jasper, + doc/conf/jasper/reference_en_gauge_start_end.jasper: + New. Templates for reference curve pdf export. + +2012-04-12 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 528, 637. + + * doc/conf/jasper/reference.jasper, + doc/conf/jasper/reference_en.jasper: + Fixed column header. + + * doc/conf/jasper/reference_gauge.jasper, + doc/conf/jasper/reference_en_gauge.jasper: + New. + +2012-04-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/check-i18n-properties.py: Checked in unsaved version. :-/ + +2012-04-11 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 656. + + * src/main/resources/messages_en.properties: + Added missing i18n strings. + +2012-04-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/check-i18n-properties.py: New. Script to check inconsistencies + of i18n properties files: Detects duplicates and keys not defined in other + properties files. Usage: + + $ find -name messages\*.properties | \ + xargs contrib/check-i18n-properties.py + +2012-04-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Generate error message when more than one Q is found for given + Q in "W auf freier Strecke". + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Added feature to adopt problems from other reports. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n for the error message. + +2012-04-11 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Use factor to calculate steps in range input mode. + +2012-04-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Increased number of fixings columns a bit. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java: + Corrected misspelled cache name. Added bebug output. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverviewFactory.java: + Added debug output. + +2012-04-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Small fixes: The service works as expected but there seems + to be a caching issue. + +2012-04-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Generate chart and deliver the image as the response of the service. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java: + Return null when looking for a fixing data column that does not exist. + +2012-04-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java: + Load ws and qs from database. Cache the fixings columns. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java: + Removed column id and added q values. + + * doc/conf/cache.xml: Added cache for the columns of the fixings. + +2012-04-05 Raimund Renkert <raimund.renkert@intevation.de> + + Fix for 'W free' validation and theme names. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Append the current Q values to theme name if the previous theme has + the same name. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Use the start km to get min/max W values in distance mode and use the + first km to get min/max W values if in location mode. + +2012-04-05 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 499. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Added validation for 'W free' using WstValueTable min/max values. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Added getter for WstValueTable. + +2012-04-05 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Defined a theme for WSPLGEN layers. + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + Made style creation more robust against nullpointers and added an + Expression class. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added a static + method createWSPLGENStyle() and some helpers to create a WSPLGEN style. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java, + src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Methods + for creating the WSPLGEN layer now take a style document. + +2012-04-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + Extract parameters from input xml and fetch fixings filters and overview + to find the columns to be viewed. + TODO: Generate chart. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java: Added + boolean result to indicate if value comes from table or is interpolated. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java: + New. Factory to fetch fixings column data from cache or database. Stub by now. + +2012-04-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java: + New. Service to generate a chart of fixings for given river and km applied + some filters. + + Usage: + $ curl http://localhost:8181/service/fixings-km-chart \ + -d @fix-overview.xml > chart.png + + The input XML is nearly the same as for the overview service. + Besides the river, filters and range it accepts elements + <km value="..."/> for passing the river km, + <extent width="..." height="..."/> for the extent of the output chart, + <mime type="..."/> for type of result. Currently ignored. + + ATM only a static fixed sized PNG image is delivered. + + * doc/conf/conf.xml: Added service to list of services. + +2012-04-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Made bullet proof for null filters and ranges. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + Fixed bug which leeds to always generating a null range filter. + +2012-04-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Squashed performance bug introduced in rev4070, which slowed down + CSV export about 245 times! + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: + Added debug output about savings when joining neighbored nodes. + +2012-04-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java: + Removed the code for filter building. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java: + New. Now contains the code for filter building. This useful because other + services like the "Fixierungs-Rohdaten am KM" service need this filtering, too. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Refactored the code to obtain a filtered list of fixings columns without + the XML serialization, too. The "Fixierungs-Rohdaten am KM" service + does not need the overview data but the ids of the fixing columns to be + displayed. + +2012-04-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java, + src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java, + src/main/java/de/intevation/flys/artifacts/services/FLYSService.java: + Derive from XMLService now. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed superfluous import. + +2012-03-30 Ingo Weinzierl <ingo@intevation.de> + + flys/issue460 (W-Differenzen: Frühere Berechnungen aus den Datenkorb werden doppelt geladen) + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed + code to find out all Outputs of this Artifacts. A method getOutputs() + had been implemented some time ago that does exactly this work. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Heavy + bugfix! Adding the current state id to the list of previous state ids + for temporary usage was no good idea! Now, the list of previous state + ids only modifified in advance(). This solves the problem of having + duplicated Outputs in the Artifact's DESCRIBE document. + +2012-03-29 Ingo Weinzierl <ingo@intevation.de> + + flys/issue366 (W-INFO / Abflusskurve, Diagramm: Umbenennen von Themen und Anzeige im Diagramm) + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Use description from ArtifactAndFacet objects for JFreeChart Series + creation. + +2012-03-28 Ingo Weinzierl <ingo@intevation.de> + + flys/issue362 (W-Info / Abflusskurve, Diagramm) + + * doc/conf/themes.xml: Adjusted text color of w and q main values for + computed discharge curves. + +2012-03-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue639: Bezugsliniendiagramm,Achsen-Intervall-Skalierung vereinheitlichen + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Render only axis ticks in meters. + +2012-03-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Let hyks have a text orientation in themes. + +2012-03-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue491, if area fill between curve and axis, draw not only + to zero. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java + (doArea): Add an artificial dataset to set lower bounds for area. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java + (addPoints): New convenience method to be used in future. + (createGroundAtInfinity, createCeilingAtInfinity): Create artificial + datasets for better areas. + +2012-03-20 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 506. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Create the date from long values instead of the year. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Added method to transform a String into an array of long values. + + * doc/conf/artifacts/winfo.xml: + changed data type from intrange to longrange. + +2012-03-20 Ingo Weinzierl <ingo@intevation.de> + + flys/issue544 (Historische ATs: Eingabeunterstützung W/Q) + + * src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java: + New service that returns information for gauges based on a specified + river. + + * doc/conf/conf.xml: Registered the GaugeInfoService. + +2012-03-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java: + Skip DischargeTables that have no time interval set or that are marked + as master DischargeTable. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Skip + DischargeTables that have no time interval set. + +2012-03-20 Ingo Weinzierl <ingo@intevation.de> + + flys/issue146 (In WINFO Diagramm Abflusskurve raus, wenn nicht gewünscht) + + * doc/conf/artifacts/winfo.xml: Do not create outputs for discharge curves + at gauge any longer. + +2012-03-20 Ingo Weinzierl <ingo@intevation.de> + + flys/issue252 (W-INFO: Wasserspiegellagenberechnung / Mitführung der Jährlichkeiten in der Diagramm-/Ergbnisausgabe) + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Added + the numeric value of a selected named main value to the WST column name. + +2012-03-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/db_layer.vm: Set the FILTER expression into double + quotes (") instead of single quotes (') which allows single quotes in + expressions. + + * doc/conf/meta-data.xml: Moved the floodmaps from kilometrage to its + parent folder. + + * src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java: + Fixed broken filter expression and set geometry type (MapServer does not + know a 'MULTIPOLYGON'). + +2012-03-16 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Remove unnecessary outputs from attributes instead of copying outs to + new attribute element. + +2012-03-16 Ingo Weinzierl <ingo@intevation.de> + + * Tagged module as 'pre2.7-2012-03-16'. + +2012-03-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Removed useless imports. + +2012-03-16 Ingo Weinzierl <ingo@intevation.de> + + flys/issue523 (W-INFO / Bezugslinienverfahren / Linieneinstellungen / Min+Max anzeigen) + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Improved the look of the minimum and maximum shape of a series. They are + now rectangles with a darker fill color as the line color is. + +2012-03-15 Ingo Weinzierl <ingo@intevation.de> + + flys/issue522 (W-INFO / Bezugslinienverfahren / Schriftgröße der Achsenbeschriftung) + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Label and + tick label fonts for axes will now always be the same. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Removed the createYAxis() method which is already implemented in an + upper class. There, the method also takes the ChartSettings into account. + +2012-03-15 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 547. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java: + Use date format with MEDIUM style. + + * src/main/java/de/intevation/flys/utils/Formatter.java: + Added date format with MEDIUM style. + +2012-03-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a new + method that returns the Bounds for a given XYDataset. Based on the + concrete type of the XYDataset, the call is dispatched to a more specific + method. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Removed the whole "range" stuff and some methods that are implemented in + upper classes. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Removed the + setXRange() and setYRange() methods. In our own code, we will use Bounds + instead of JFreeChart's Range instances to save range/bounds information. + This is necessary to save information which is not not from type double + (which is the case in Timeseries charts). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Replaced + usage of Range with Bounds in the whole class. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Adapted the method signature of zoom() and zoomX(). + +2012-03-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Copied the adjustAxes() method from XYChartGenerator which enables axes + label font sizes. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Removed unnecessary axes creation method which is implemented in upper + classes. + +2012-03-14 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 640. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Remove all unnecessary output settings from attributes. + +2012-03-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial for flys/issue358, rough stub for legenditem aggregation. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Added rough stub for legend aggregation. + +2012-03-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Fixed broken XML syntax. + +2012-03-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Modified the datacage structure of 'floodmaps'. + +2012-03-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java: New. + This Artifacts allows loading 'floodmaps'. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added a + new Facet type "floodmap.floodmaps" which are created by + WMSFloodmapsArtifact. + + * doc/conf/artifacts/winfo.xml: Registered the "floodmap.floodmaps" facet + for "floodmap" output. + + * doc/conf/conf.xml: Registered the new WMSFloodmapsArtifact. + + * doc/conf/themes.xml: Added a theme for the "floodmap.floodmaps" facet. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n string for + "floodmap.floodmaps" title. + +2012-03-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Improved datacage configuration to serve + floodmaps. + +2012-03-05 Ingo Weinzierl <ingo@intevation.de> + + flys/issue566 (ÜSK: Formalien in der Parametrisierung) + + * src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java: + Override getLabelFor() method to return better I18N strings for selected + floodplain option. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added options + for floodplain (active/inactive) and adapted a german I18N string. + +2012-03-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue 528 for csv. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Fixed column order, reworked todos. + +2012-03-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Fixed column order. + +2012-03-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Stub to export the "W (cm)" column conditionally on Gauge presence. + +2012-03-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/StepCSVWriter.java: + New utility to handle csv rows of more "dynamical" length. + +2012-03-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/StepCSVWriter.java: + New utility to handle csv rows of more "dynamical" length. + +2012-03-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue501 (manual points have two legend entries). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Respect wish to not have a legend entry. + +2012-03-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue636 (cross-section: name of waterlevel facets). + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Corrected name for waterlevel facets. + +2012-03-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix flys/issue615 (datacage: events for fixations). + + * doc/conf/meta-data.xml: Adjusted to make loading single events + possible. + +2012-03-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Dontcrash on flys/issue647 (NaNs from WstValueTable interpolation). + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Do not add data pairs where a NaN is present. + +2012-03-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Cosmetics, doc. + +2012-02-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Added functions to be used for fitting in + the "Fixierungsanalyse" and "Extremwertermittlung". + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: New. + Abstract base class for functions to fit. Provides the name of the function, + a short description, the names of the parameters and an initial parameter guess + for the fit processe. Sub classes have to overwite the function evaluation and + the partial derivative of the function in respect to the parameters. + + TODO: Add a meachnism for the inverse function (needed for AT export) and + the first derivative (needed for the respective diagram). + + * src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java: + New. Factory to fetch a function by its name. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java: New. + exp: W(Q) = m * a^Q + b + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java: New. + quad: W(Q) = n*Q^2 + m*Q + b + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java: New. + linear: W(Q) = m*Q + b + + * src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java: New. + log-linear: W(Q) = a*ln(m*Q + b) + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java: New + log: W(Q) = m*ln(Q + b) + + * src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java: New. + pow: W(Q) = a*Q^c + d + + !!! This power function is new in the pool of functions to be fit. !!! + See my mail "Manuelle Punkte in der Fixierungsanalyse" 2011-10-27 for details. + The function exp-new found in the old FLYS function pool is omitted + because it is worthless and was maybe never used. + + * src/main/java/de/intevation/flys/artifacts/math/fitting/App.java: New. + Small test driver to check if the fitting is working. The points to + fit are read from stdin the function to fit is determined by the + system property 'function'. Example usage: + + $ mvn -e \ + -Dfunction=linear \ + -Dexec.mainClass=de.intevation.flys.artifacts.math.fitting.App exec:java <<EOF + 357.390696917 7546.72096163 + 61.4291036312 1334.54835721 + 799.962128234 16836.7698076 + 126.52761023 2703.69789985 + 900.448553398 18955.0578748 + EOF + +2012-02-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages_de.properties: + Added ommitted translations. + +2012-02-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + fix flys/issue638. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java + (doArea): Ract to WKms as upper/lower area data again. + +2012-02-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix flys/issue637. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java, + src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Modified translations. + +2012-02-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + - Calculate the extent of the river by the extents of the fixings. + Reason: The river Elbe has only has fixings up to km 351. The other half + of the river is empty which results in a sparse looking overview. + - Add the name of the river as name attribute to resulting <river> element. + + * contrib/fixoverview2html.xsl: New. Demo XSL transformation to turn + the output of the overview service directly into HTML. Used in the + client a variant of this script could be used for producing the content + of the assistance widget. Usage: + + $ curl http://localhost:8181/service/fixings-overview \ + -d @fix-overview.xml | \ + xsltproc contrib/fixoverview2html.xsl - \ + > fixings-overview.html + +2012-02-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java: + Made the filter mechanisms available via the incoming XML document. + + 1 - range: Simply add a <range from="..." to="..."/> element next to the + <river> element. Optional. Defaults to full extent. + + 2 - filters: Add a <filter> element next to the <river> element. + Optional. Defaults to accepting all. + The <filter> element can contain the following elements: + + <column cid="..."/>: Creates an IdFilter. + <date when="..."/>: Creates a DateFilter. + <date-range from="..." to="..."/>: Creates a DateRangeFilter. + <sector-range from="..." to="..."/>: Create a SectorRangeFilter. + <not>...</not>: Creates a NotFilter. The nested element is negated. + <and>...</and>: Create an AndFilter: The nested elements are 'and'ed. + <or>...</or>: Create an OrFilter: The nested elements are 'or'ed. + + These filters need testing! + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Made date format a public constant. + +2012-02-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Added a filter mechanism for generating output. + + There are two kinds of filters: + + 1 - A range. Defaults to [-Double.MAX_VALUE, Double.MAX_VALUE] + The resulting sectors are cut to this range. Sectors outside + this range are omitted. + + 2 - column filters: Given a fixing column they can decide to keep + or not to keep it. Following filters exist: + + - IdFilter: Keep column if column id matches. + - DateFilter: Keep column if column date matches. + - DateRangeFilter: Keep column if column date is in range. + - SectorRangeFilter: Keep colum if one of its q sectors is in given range. + - NotFilter: Negates another nested filter. + - AndFilter: Keep column if all nested filters accept column. + - OrFilter: Keep column if at least one of the nested filters accepts it. + +2012-02-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + Refactored to build the Q sectors once at construction time and not + every time output is generated. + This will ease the job of applying filters to the Overview. + +2012-02-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Service to generate the data needed to build the "Fixerungen pro Fluss Uebersicht" + + * src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java: + New. A service that serves an XML overview version of the fixings of a given river. + + The input documents look like this: + + <?xml version="1.0" encoding="UTF-8"?> + <fixings> + <river name="Saar"/> + </fixings> + + The output documents looks like this: + + <?xml version="1.0" encoding="UTF-8"?> + <fixings> + <river from="0.0" rid="1" to="93.0"/> + <events> + ... + <event cid="85" date="29.01.1995 00:00" name="Fixierungen/0-93_1988-2001.wst"> + <sector class="0" from="82.7" to="92.85"/> + </event> + <event cid="86" date="13.11.1996 00:00" name="Fixierungen/0-93_1988-2001.wst"> + <sector class="2" from="0.0" to="50.599999"/> + <sector class="1" from="50.6" to="65.89"/> + </event> + ... + </events> + </fixings> + + The <river> element contains the extent of the whole river + and its db id. + The <events> sections contains serveral <event> elements. + They have a meassure date, db id, a name and a number of <sector>s. + These sectors are q classified from/to ranges. Classes are: + + 0: smaller (MNQ+MQ)/2 + 1: (MNQ+MQ)/2 to (MQ+MHQ)/2 + 2: (MQ+MHQ)/2 to HQ5 + 3: greater HQ5 + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java: + New. Cacheable instance of the overview. + TODO: Apply a filter mechanism when generating the output. + + * src/main/java/de/intevation/flys/artifacts/model/FixingsOverviewFactory.java: + New. Fetched the fixing overviews from cache if configured. + + * doc/conf/conf.xml: Added the service. + * doc/conf/cache.xml: Configured the cache for the fixing overviews. + +2012-02-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxQ): + Argh! Forget to check in the range method. + +2012-02-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxQ): + Symmetrical to getMinMaxW() add two methods to find min/max Q for a given + km or a range. The range method is maybe a bit slow. + +2012-02-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxW): + Added signature to give w extend for a given km range. + +2012-02-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxW): + Added method to find the w extent for a given km. Useful + for validating "W auf freier Strecke". + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: + Removed superfluous import. + +2012-02-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java, + doc/conf/artifacts/winfo.xml: + Renamed state data fields: wq_mode -> wq_isq + wq_free -> wq_isfree + wq_selection -> wq_isrange + +2012-02-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Write the description instead of the Q value to CSV file. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Added parameter to overriden method. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Get Qs without range. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Adjusted i18n string for CSV metadata. + +2012-02-17 Ingo Weinzierl <ingo@intevation.de> + + Part II/III flys/issue497 (Diagrammeigenschaften in Zeitseriendiagrammen) + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Apply legend specific settings (show/hide). + +2012-02-17 Ingo Weinzierl <ingo@intevation.de> + + Part I/III flys/issue497 (Diagrammeigenschaften in Zeitseriendiagrammen) + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Moved + adjustPlot() from XYChartGenerator to ChartGenerator which enables the + TimeseriesChartGenerator to call this method as well. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Call adjustPlot() in generateChart() to apply the settings specific to + gridlines in the timeseries plot. + +2012-02-16 Raimund Renkert <raimund.renkert@intevation.de> + + Refactored the wq data fields. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Changed the wq data fields to boolean values. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Changed the wq data fields to boolean values and added method that + returns the km input mode. + +2012-02-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Fixed W->Q conversion for "W fuer ungleichwertige Abflusslaengsschnitte." + +2012-02-16 Ingo Weinzierl <ingo@intevation.de> + + flys/issue509 (Dauerlinie: Q-Achse sollte bei 0 beginnen) + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Set the lower bounds of the Q axis to 0 to avoid displaying negative + discharge values. + +2012-02-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java, + src/main/java/de/intevation/flys/artifacts/model/WKms.java: + (guessWaterIncreasing): Removed from interface. + +2012-02-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue150 (exposure of gravitational anomalies) + + * src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java, + src/main/java/de/intevation/flys/artifacts/model/WKms.java: + (guessWaterIncreasing): In analogy to W->WQ->WQKms defined and + implemented. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + (needInvertAxis): Changed Parameter type to WKms (was WQKms). + (doW): Use in this case weaker wkms cast to find out whether axis + has to be inverted. + +2012-02-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: Fixed + SQL statement to fetch hyk formations for rivers with 'km_up' = 0. + +2012-02-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Another partial fix for flys/issue499: Do the W to Q conversions + needed for "W am Pegel" correctly. + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Repaired getQsForW(): The mapping from W to Q is not unique! There + could be more then one Q having the the same W. + Ws are not strictly monoton/sorted so doing a binary search on this + is just a fail. We now scan them linearly. + + XXX: The whole class is mess. The scaling stuff is a stupid + and there is no caching. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Fetch the master discharge table for converting Ws to Qs. Handle + the case that there are more Qs for a given W. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Adjusted to new semantic. + +2012-02-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Fix flys/issue500: text-orientation for texts. + + * doc/conf/themes.xml: Change default text orientation for text + annotations. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Minor cosmetics. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Parse and apply text rotation field. + +2012-02-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Partial fix for flys/issue499 (Wasserspiegellagen: Berechnung für W frei und Pegel kaputt) + There are still validation issue in the client. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Fixed state evaluation for "W auf freier Strecke"/"W am Pegel". + There is still an issue in the client with the input validation + which prevents entering the right W values for + "W auf freier Strecke". :-/ + +2012-02-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Make it compilable again. + +2012-02-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Fix flys/issue500: text-backgrounds for manual points. + + * doc/conf/themes.xml: Added text-related style items to manual + point themes. + +2012-02-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Fix flys/issue500 + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Parse whether to show text background. Apply to textannotation. + +2012-02-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue490 + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Pass artifact and facet for doAnnotation. + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + Use AddScaleFunction instead of LinearFunction. + + * src/main/java/de/intevation/flys/artifacts/math/AddScaleFunction.java: + New. f(x) = m*(x+b). I know its aequivalent to m*x + m*b but it + makes more clear that the datum [m] (PNP) is substracted before the + scaling to cm is done. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Bugfix: take + care on empty ArtifactAndFacet objects in doAnnotations(). + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java: + Inherits from ReferenceCurveGenerator now which really simplifies it a lot. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Added to methods to be overwritten by sub classes. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Adjusted i8n. + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + Indexed access to getInCm. + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Simplified. Do not provide any data to blackboard. Only side effect the + call context. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Added convinience method to i18n string with defaulting to key name. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Label the axis according the scale types of the data. + TODO: Let the NormalizedReferenceCurveGenerator be a sub class of + this. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: i18n for the reference curve axes. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java: + Fixed wrong double array dimension for PDF exports and write correct + differences into PDF. + +2012-02-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java, + src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + Adjust function to deliver data provider ('blackboard') keys. + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Change the way we exploit the blackboard-mechanism. TODOs added. + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Argh! Finally found the stupid bug in the W~W relation: + Used iQ1 index on W2(Q2). + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Improved error messsages even more. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Adjusted messages. + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Forget to put new created WWAxisType onto blackboard. + +2012-02-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + Adjust offset of linear function by same factor as the values. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Write + correct min and max values for date axes into the info document. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Enabled zooming for timeseries charts. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/Bounds.java, + src/main/java/de/intevation/flys/jfree/TimeBounds.java, + src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Added a method + applyBounds(ValueAxis, int) that might be used to adapt the range of the + axis to the bounds adding a space to the left and right. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Defined + new abstract methods for setting and getting Bounds. Modified and + renamed getValueAxisRange(). This method is now called + getValueAxisRangeFromRequest() and returns no longer a Range object but + a String array that consists of the raw string values speicified in the + request document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Implemented the missing method getDomainAxisRange(). This method returns + a Range object based on the String array returned from + getValueAxisRangeFromRequest(). + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/TimeBounds.java: Added new + methods getLowerAsDate() and getUpperAsDate(). The toString() method + will now return a string that contains a human readable date string. + + * src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Made 'lower' + always be smaller than 'upper' in the default constructor. + +2012-02-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Give more precise message when an error occurs in W~W relation. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Improved error messages. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Modified + and renamend getDomainAxisRange(). This method is now called + getDomainAxisRangeFromRequest() and returns no longer a Range object but + a String array that consists of the raw string values specified in the + request document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Implemented the missing method getDomainAxisRange(). This method returns + a Range object based on the String array returned from + getDomainAxisRangeFromRequest(). + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a + helper function to determine the min and max bounds (x and y) for + TimeSeriesCollections. + +2012-02-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/TimeBounds.java, + src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Removed + useless imports. + +2012-02-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Add accessors to relative heights. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Add relative heights (to gauge) to csv export. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * pom.xml: Added dependency to GeoTools swing module. + + * src/main/java/de/intevation/flys/artifacts/map/PrintMap.java: Standalone + demo application to print WMS layers to file. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/TimeBounds.java, + src/main/java/de/intevation/flys/jfree/DoubleBounds.java, + src/main/java/de/intevation/flys/jfree/Bounds.java: New model classes that + should be used for adapting axes ranges later. + +2012-02-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + Generate a valid intial i18n name. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Pass call context to calculation. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + flys/issue485 (Themen können umgenannt werden, dies wird nicht in der Legende reflektiert) + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Use ArtifactAndFacet.setFacetDescription() to set the description for + themes which are stored in the Collection's XML attribute. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Some refactoring of doXXXOut() methods. We pass the ArtifactAndFacet + objects of doOut() into those concrete doOut() methods which allows us to + generate series names for chart curves. + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Replaced dashes by underscores in entities + to ease translation. + +2012-02-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Fixed problem with including Y-Zeros. + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Removed superfluous imports. + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow points in "new chart"s. + + * doc/conf/artifacts/chart.xml: Added manualpoint facets to + compatibility lists. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/Style.java: New. A Style object + needs to implements a method applyTheme() which takes a + XYLineAndShapeRenderer. + + * src/main/java/de/intevation/flys/jfree/XYStyle.java: New. This subclass of + Style modifies the XYLineAndShapeRenderer specified in applyTheme(). + + * src/main/java/de/intevation/flys/jfree/StyledSeries.java: New. This + interface defines two methods getStyle() and setStyle() to adjust and + retrieve the Style of a series. + + * src/main/java/de/intevation/flys/jfree/StyledTimeSeries.java: New. + Implementation of StyledSeries that subclasses JFreeChart's TimeSeries. + + * src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: Removed the + code for adapting a XYLineAndShapeRenderer. Instead of implementing this + stuff in StyledXYSeries itself, this instance now implements StyledSeries + and stores an instance of XYStyle. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Create new instances of StyledTimeSeries now which enables styling in this + chart. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Enabled + styling of series for all series that implement StyledSeries. + +2012-02-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(relateWs): + Be more conservative about arrays and indices in "Bezugslinienverfahren". + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow areas in new chart/longitudinal_section. + + * doc/conf/artifacts/chart.xml: Added area facet to compatibility + list. + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue490. Allow CollisionFree..Annotations to collide with + non-collision-free annotations. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotationEntity.java: + New, to take advantage of cheap instanceof operator. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Only avoid collisions with members of same family (i.e. allow + collision with annotations of other types). + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added themes for historical discharge curves and + the differences to a reference curve. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Some + bugfixes and improvements: + 1) take only historical discharge tables into account for calculation + 2) use the correct values for computing differences + 3) moved timerange preparation into an own method + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java: + Fix call to StringUtils.join . + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n string for waterlevels (from datacage). + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java: + Locale-format multiple double values also. + +2012-02-09 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Registered a new facet for difference curves + to the historical discharge output. + + * src/main/java/de/intevation/flys/artifacts/model/HistoricalWQTimerange.java: + New model that is able to store a further double value "diff" besides a W, + Q and a Timerange. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Create + new HistoricalWQTimerange instances with difference between the reference + discharge table and the historical discharge tables. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: New type + for historical differences. + + * src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: Cast + Timerange array in getTimeranges(). + + * src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java: + New Facet for historical discharge difference curves. + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java: + Create new Facets for the difference curves if the processed data are from + type HistoricalWQTimerange. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Added doOut() path for difference curves. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java: + Increased the size of a double array to be able to get results from + HistoricalWQTimerange. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translation for warning + if no reference discharge table was found for the specified gauge. + +2012-02-09 Raimund Renkert <raimund.renkert@intevation.de> + + Added PDF export to reference curve calculation. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Added PDF export. + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java, + doc/conf/artifacts/winfo.xml: + Add facet for PDF export to state. + + * src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java: + New. Datasource for JasperReports containing reference curve data. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for JasperReports template file and calculation mode. + + * doc/conf/jasper/reference.jasper, + doc/conf/jasper/reference_en.jasper: + New. Templates for reference curve PDF export. + +2012-02-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java(getReferenceEndKms): + Prevent duplicates in end kms for reference curve calculation. + +2012-02-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + doc/conf/artifacts/winfo.xml: Renamed data item names to allow + translations. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Give (Normalized)ReferenceCurveFacets are more appropriate + description (to be seen in client). + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Prepare Reference curves to eat multiple locations as 'Ziel'. + + * src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java: + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java: + New. State to provoke multi_location_panel. + + * doc/conf/artifacts/winfo.xml: Made end state of ref curves a (new) + EnterMultipleLocationState. + +2012-02-08 Ingo Weinzierl <ingo@intevation.de> + + flys/issue483 (Historische Abflusstafeln ohne Ergebnis) + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Add + a problem for the calculation report if no discharge tables were found + for the given timerange. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translation for error + messages created by Calculation6. + +2012-02-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/Formatter.java: + Format kms in error reports at least with one digit after + the decimal separator. + +2012-02-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix flys/issue468 (Fehler beim Projekt-Duplizieren) + + * src/main/java/de/intevation/flys/exports/ReportGenerator.java: + Always create a new XML document when calling report generation. + XXX: There is a bug somewhere which calls error reporting twice + when cloning a collection. Speculation: It has something to do with + the settings stuff. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Remove superfluous imports. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java: + Added missing Override annotation. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Handle Manual Point Facets, added TODO. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + Subclass BlackboardDataFacet to repair areas over cross sections. + +2012-02-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Let text + and line annotations placed at x or y axes always be in foreground. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue474 (manual points in reference curves). + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/manualpoints.xml: + Add manualpoints to lists just so that really everybody knows. + + * doc/conf/themes.xml: Add styles for manual points in ref curves. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Add ref curve chart types. + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Handle manual point facets. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Fix flys/issue474. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translation for + normalized_reference_curve. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue475. + + * doc/conf/themes.xml: Register theme for reference_curve_normalized. + +2012-02-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Add a "/" to the + URL of the user wms if the URL configured in conf.xml doesn't end with + a "/". + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue472. + + * doc/conf/themes.xml: Added theme for discharge_curve manualpoints. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added discharge_curve as chart type. + +2012-02-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix flys/issue484 ((i18n: Ungleichwertige... Report)) + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Fixed key spelling. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue478 (Manuelle Punkte: Stil nicht änderbar). + + * doc/conf/themes: Map correct theme to manualpoint themes. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix flys/issue472 . + + * doc/conf/artifacts/winfo.xml: Add manual points to compatibility + list of cross_sections. + + * doc/conf/artifacts/manualpoints.xml: Add manualpoints to list of + generated facets. + +2012-02-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Commented styling option for show area until + area calculation works. + +2012-02-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + i18n the km of the error report. + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Fixed potential race conditions. + + * src/main/java/de/intevation/flys/utils/Formatter.java: Added + formatter for error report kms. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + Removed superfluous imports. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Commented out some imports. They are used be out commented code. + +2012-02-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java: + Use the correct km key for an unspecific km for fetching the whole river + annotations. + +2012-02-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Added missing config of chart info generator + of normalized reference curve. + +2012-02-07 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Fixed wrong chart info generator name for historical + discharge curves. + +2012-02-07 Raimund Renkert <raimund.renkert@intevation.de> + + Added PDF export for historical discharge curve calculations. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java: + Implemented PDF export for calculation results. + + * src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java: + New. Datasource for JasperReports. + + * doc/conf/artifacts/winfo.xml: + Added facet for PDF export to historical discharge curve output mode. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for historical discharge curve export. + + * doc/conf/jasper/historical-discharge.jasper, + doc/conf/jasper/historical-discharge_en.jasper: + New. Templates for JasperReports PDF creation. + +2012-02-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Handle WWQQs, extended CSV export of reference curves. + +2012-02-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Recactored, moved Formatter accessors to base class AbstractExporter. + +2012-02-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let reference curve calculation result in specific WWQQ, extended CSV + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java + (getWW,getWWQQ): Renamed and changed result type. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java, + src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Result in WWQQs, not in WWs. + +2012-02-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Log error as warning. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/LinearFunction.java: + New. Linear function f(x) = m*x + b. + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + Do the normalizing. Cascading functions is not required. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveInfoGenerator.java: + Added missing chart info generator for the normalized reference curves. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: Fix i18n. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + Added optional boolean flag to indicated if the data should be 'normalized'. + TODO: Build the cascading normalising function call chain. + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Fetch WWAxisTypes from call context to do the right scaling. + +2012-02-06 Raimund Renkert <raimund.renkert@intevation.de> + + Added service for discharge infos at a specific gauge. + + * doc/conf/conf.xml: Added service factory entry. + + * src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java: + New. Returns description, start year and end year of discharges at a + specific gauge. + + * src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java: + Return a more specific ui provider string. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Registered generator for normalized reference curves. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added "reference_curve_normalized". + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Added facets for normalized reference curves. + + * src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java: + Generator for normalized reference curves. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added config for "reduzierte Bezugslinie". + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added error report. + +2012-02-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Set + proper bounds for date axis elements; tell the transformation matrix which + type it is (number/date). + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Include location description string in csv output of referencecurve- + exporter. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: Added constructor call. + * src/main/java/de/intevation/flys/artifacts/model/WWQQ.java: New. + Stores the Qs for the Ws, too. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: Create + WWQQs instead of WWs. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Added further i18n stubs and slightly more data. + +2012-02-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(relateWs): + Return the Qs of the Ws, too. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + Adjusted to cope with the return Qs. TODO: Create WQWQ or WWQQ dataset + for storing the result. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Added further i18n stubs. + Also added a second Y axis (experimental, to ease axis labeling etc.). + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Register new export output and csv + facet for reference curves. + + * doc/conf/conf.xml: Register Exporter for reference curve. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java: + Primitive exporter, bland copy of another one. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Enabled some i18n of labels. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Basic i18n for reference + curves added. + +2012-02-06 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Registered the HistoricalDischargeCurveInfoGenerator. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveInfoGenerator.java: + New. This info generator returns information of a + HistoricalDischargeCurveGenerator. + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Add an + attribute "axistype" to axes nodex based on the JFreeChart Axis type. + Number axes get a "number", date axes a "date". + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Defined an + abstract method getRangesForAxis(). + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: Awaits + now an instance of ChartGenerator instead of XYChartGenerator. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Implemented the getRangesForAxis() method (copied from XYChartGenerator). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added + @Override annotation to getRangesForAxis(). + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + Cosmetics. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Add CSV facet (not yet evaluated). + +2012-02-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java: + New. This OutGenerator exports historical discharge curves to CSV and PDF. + Currently, only the CSV export is implemented! + + * doc/conf/artifacts/winfo.xml: Registered a new Output CSV for historical + discharge curves. + + * doc/conf/conf.xml: Registered the HistoricalDischargeCurveExporter. + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java: + Generate new Facets for CSV and PDF output. + + * src/main/java/de/intevation/flys/utils/Formatter.java: Added new functions + that return number formatters for historical discharge curves and a date + formatter for short dates. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings for CSV header of + historical discharge curve export. + +2012-02-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Adjusted to name change in River ('hibernate fix'). + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Adapted the data type of W/Q input values + for historical discharge curve calculation (intarray -> doublearray). + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java: + Adapted the data type of W/Q input values. + +2012-02-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + First steps to serve the data in cm if we are are gauges only. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Fetch map gauge station -> gauge datum from backend for reference curve. + + * src/main/java/de/intevation/flys/artifacts/math/LinearFilterFunction.java: + New. Linear transforms another function. + + * src/main/java/de/intevation/flys/artifacts/math/FilterFunction.java: + New. Allows cascading functions. + + * src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java: + New. Classifier what kind of axis types are needed. + + * src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java: + Removed. Is now obsolete. + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Stores gauge station kms for start and end km if they are any. + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Should generate a WWAxisTypes classifier via side effect to the + call context. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + Figure out for each start/end km if its a gauge station and store this + information in the result WWs. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Uses the WWAxisTypes classifier now to generate the right data. + TODO: Use the blackboard object. + +2012-02-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java: + Removed superfluous imports. + +2012-02-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Set number of interpolation steps for relation curve to 200. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Do not sort the XYSeries. + +2012-02-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveInputState.java: + Removed. Was stub. + +2012-02-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved Reference Curves. + + * doc/conf/artifacts/winfo.xml: Add start/end input step for reference + curves. + + * doc/conf/themes.xml: Add theme for reference curve. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Disable start/end point-hack for reference curve. Go with 'live' + values. + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + i18n. + + * src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java: + New. State to enter location. + + * src/main/java/de/intevation/flys/artifacts/states/InputDoubleState.java: + New. + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Take WW name to display in themepanel. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translations. + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Use + the current date for discharge tables which doesn't have a stop time set. + A warning message is written to log. + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java: + Generate report facet before leaving the computeXXX() method when no + calculation results has been computed. + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function + that returns the name of a reference gauge (for historical discharge + curves). + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Create title, subtitle and axes labels for charts of this type. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added title, subtitle and axes + labels for historical discharge curves. + +2012-02-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Fix. + +2012-02-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translations for + states (will be shown in client). + +2012-02-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Ja!vadoc. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Declare getYAxisWalker as abstract to avoid weird issue with + overriden methods of this name. + +2012-02-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java: + Use the WW.ApplyFunctionIterator to fetch the data. + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java: + Removed superfluous imports. + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Registered a ReportFacet for historical + discharge curve report. + + * doc/conf/conf.xml: Registered a ReportGenerator for historical discharge + curves. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Add + problems if we were not able to find a Q for a given W. + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java: + Generate a ReportFacet if there were problems during calculcation. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added error messages for the + case that we were not able to find a Q for a given W while calculating + historical discharge curve data. + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Improved adding new data for historical discharge curves: skip NaN + values; use JFreeChart's Day TimePeriod instead of Second. + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: Refactoring: + moved addDatasets(), applyThemes() and some other methods into + ChartGenerator; enhanced the AxisDataset interface. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Implemented necessary abstract methods and improved internal AxisDataset + class (added new methods). + +2012-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a + function that expands a given range. Take care on NaN in getRanges(). + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Prevent of NullPointerExceptions in isMinimumShapeVisible() and + isMaximumShapeVisible(). + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Create new AxisDatasets and new TimeSeriesCollections for each Facet. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: Added a + method getTimerange(idx) that returns the Timerange at a given index. + + * src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeFacet.java: + Return the correct WQTimerange object in getData(). + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: More + refactoring: the AxisDataset is defined by an interface in ChartGenerator + now. Each subclass of ChartGenerator should implement its own AxisDataset. + This allows us to provide multiple XYDataset types in different charts. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Implemented some necessary methods (abstract definitions of parent class) + and create new empty timeseries charts. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartHelper.java: New helper + class for working with charts. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Removed useless import. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: More + refactoring: moved more base code from XYChartGenerator to its parent + class ChartGenerator. + +2012-02-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + Refactored. Use supers static field. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Refactored. Use static field. + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java + (getMinMax, getRiverMinMax): Refactored. Moved to FLYSUtils. + + * src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java: + Add so-called javadoc. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: Moved + further base code from XYChartGenerator into its ChartGenerator. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Override generateChart() instead of generate() which is now implemented + in ChartGenerator. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + New. This ChartGenerator should be used for timeseries charts. Currently, + this class is a stub only! WORK IS IN PROGRESS! + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Subclasses TimeseriesChartGenerator now instead of XYChartGenerator, + because historical discharge curve charts will have a time x axis set. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: Moved some + basic stuff from XYChartGenerator into ChartGenerator. + +2012-02-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/TimeseriesStepChart.java: + Added standalone demo app for evaluating different timeseries charts. + +2012-02-02 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 466: CSV export for chart themes. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Export a CSV file if the requested format is 'csv'. + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + Generate the CSV file containing X-Y-data of all activated themes. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Moved code to load values of a discharge table into an own static + function to be able to reuse it in Calculation6. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: + Implemented the findValueForW(). + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fake some reference curve input values to have working prototype + to work on. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Syntax-stunt fake reference inputs. + + * src/main/java/de/intevation/flys/artifacts/model/WW.java + (getW1): Accessor for first w at index (for the raw ww). + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java + (doReferenceOut): Plot the raw W-over-W. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Create time + millis for timerange used in Calculation6. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Added + the first step of the calculation: fetch relevant discharge tables based + on the given input parameters. The calculated values are not the right + ones! Finding Ws and Qs in discharge tables is still not implemented! WORK + IN PROGRESS! + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java: + Create facets for each WQTimerange object calculated by Calculation6. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Timerange.java: Added a + new constructor that takes Date objects for start and end time. + +2012-02-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/W.java: + Forget to create ws data in constructor. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Replaced Reference Curve input state + with LocationSelect-State for debugging purposes. Add output to + reference.curve- state. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Register ReferenceCurve*Generators. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + Cosmetics. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Added pro forma facet. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + Added comment. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added reference curve facet type. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Fetch + necessary parameters for 'historical discharge curve' calculation and call + Calculation6 with those parameters. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: + Modified default constructor and calculate() signatures and added a + parameter check which is evaluated before the calculation starts. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ReferenceCurveInfoGenerator.java: + Added outline of a new chart-generator. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Timerange.java: New. + This class might be used to store timeranges. Start and end time are + stores as long (milliseconds since january 1, 1970). + + * src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: + New. This class should be used to save Ws, Qs and timeranges. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added helper + methods to extract int[] and double[] from string. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Registered new facet type + 'historical_discharge.historicalq' to the 'historical_discharge' output. + + * doc/conf/conf.xml: Registered new HistoricalDischargeCurveGenerator for + output type 'historical_discharge'. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new facet type for HISTORICAL_DISCHARGE_Q. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + New. This ChartGenerator is used to generate new charts for historical + discharge curves. WORK IN PROGRESS! + + * src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: New. + This class should 'compute' the historical discharge curves. WORK IN + PROGRESS! + + * src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeFacet.java: + New. This Facet is used during the calculation of historical discharge + curves. + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added stubs + to trigger the calculation of data used for generating historical + discharge curve charts. + +2012-02-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Removed needless imports. + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages_de.properties, + src/main/resources/messages_de_DE.properties: + Fixed "W bei ..m" -> "W fuer ...n" . + +2012-02-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Avoid NPE, add warning to log to not forget about it. + +2012-01-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Fixed problems with unformatted numbers in error message. + +2012-01-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java: + Override getLabelFor() to return the I18N string for the selected + evaluation mode. + +2012-01-31 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Modified types of parameters in the + 'historical discharge curves' transitions. + +2012-01-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Fix transition type (Stupid Bug 1.0 reverse). + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceGaugeState.java: + Override getLabelFor() method defined in DefaultState to return the name + of a Gauge based on the official number which is stored in the + parameterization. + +2012-01-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow manual points in more diagram types. + + * doc/conf/artifacts/winfo.xml: Add respective facet types to + compatibility lists of output modes. + + * doc/conf/artifacts/manualpoints.xml: Mention facet types. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added ChartType enum to ease later iteration. + (IS.MANUALPOINTS): Added helper. + + * src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java: + Help artifact figuring out which data to provide by passing facet + name. + + * src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java: + Respond to getPointData with correct data item, depending on facet + name. + + * src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java: + Iterate over chart types. Add facets if corresponding data is found. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Handle manual point facets. + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Clone + StateData model objects to save parameters in this Artifact - create + new StateData instances only if no StateData model was found for a + parameter. This solves the problem of loosing the type of a StateData. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Implemented a getLabelFor() method that is used to format a parameter + value. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + Adapted method signature of transform(). + + * src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java: + Override getLabelFor() method to create a well formatted label for min/max + values. + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StateFactory.java: + Bugfix: use correct order of parameters in DefaultStateData constructor. + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Fixed a stupid bug. Use + ValueCompareTransition instead of DefaultTransition to evaluate values. + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java: + Write default values for min and max items into the DESCRIBE document. + +2012-01-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Added field 'startKm' and 'endKm' to make it easier to associate + gauge to km to return Ws in cm if km is at a gauge. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + Construct the WWs with startKm and endKm. This is necessary because + if an error occurs in calcuting an in between km in a list of end kms + the index does not correspond to the input value any more. + +2012-01-30 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added transitions for "historical discharge + curves" calculation. + +2012-01-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + (doPoints): Skip 'inactive' points. + +2012-01-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Removed the createNormalized() method because it did not + solve all problems with the transformation of the W~W data we have. + + - We need to shift the values to be based in (0, 0). + - We need to linear transform the values if they are at gauges. + - Copying the data is memory expensive. + + Therefore there is now a new inner class ApplyFunctionIterator + that is able to transform the values in an iterator like manner. + The transform functions default to the identity. + + * src/main/java/de/intevation/flys/artifacts/math/Sub.java: New. + Simple function that subtract a scalar from the parameter. + + * src/main/java/de/intevation/flys/artifacts/model/W.java: Added + method minWs() to calulate the minimal W of the data. + + * src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java: + getData() returns a WW.ApplyFunctionIterator with identity transform. + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + getData() returns a WW.ApplyFunctionIterator with a base shift to (0, 0). + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Added method createNormalized() to shift the data to start in (0, 0). + + * src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java: + Returns the 'normalized' data of the reference curve. + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java: + New. Facet for the normalized W~W relation. + TODO: Implement the on-the-fly creation logic. + + * src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java: + New. Facet for the W~W relation. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: Cosmetics. + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java: + Added stub loop for creating facets. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Cosmetics. + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Call the 'Bezugslinienverfahren'. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + I18N for the 'Bezugslinienverfahren' error messages. + +2012-01-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Better theme for manual points. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Theme text part of manual points. Offset it a bit. + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + Fixed stupid bug. + +2012-01-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceGaugeState.java, + src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java, + src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java: + New. States used in the 'historical discharge curve' calculation. + +2012-01-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java: New + state that eases adding min/max value pairs to describe document. + + * src/main/java/de/intevation/flys/artifacts/states/IntRangeState.java: + New. Subclasses MinMaxState and allows adding min/max integer value pairs. + +2012-01-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: Moved + code to add items to a data node for dynamich UI into an own method. + +2012-01-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java: Removed + useless import. + +2012-01-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings which are used n + the calculation "historical discharge curve". + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: + New. Calcutation to be created from WINFOArtifact + for the 'Bezugslinienverfahren'. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Added TODO about optimization of the 'Bezugslinienverfahren'. + Added number of default samples of the W~W relation. + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + Added convinience constructor to store the calculation results. + + * ChangeLog: Removed false TODO. + +2012-01-27 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java, + src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + Read jasper template file from resources to support i18n reports. + + * doc/conf/jasper/wdifferences.jasper, + doc/conf/jasper/duration.jasper, + doc/conf/jasper/computed-discharge.jasper, + doc/conf/jasper/waterlevel.jasper: + Updated report template. Resized left margin. + + * doc/conf/jasper/computed-discharge_en.jasper, + doc/conf/jasper/duration_en.jasper, + doc/conf/jasper/wdifferences_en.jasper, + doc/conf/jasper/waterlevel_en.jasper: + New. Templates for english reports. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for template files and modes. + +2012-01-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Prevent second Legend Entry for points (prior was one for the + TextAnnotations and one for the points). + +2012-01-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Blindly render Text of manual points if it does not collide with + other text. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Handle TextAnnotations, create some for manual points. + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + Added setter for TextAnnotations, documentation. + +2012-01-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + +2012-01-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Refactored class hierachy to integrate model for W~W: + + NamedObjImpl + \-- W + +-- WW + \-- WQ + +-- WQDay + \-- WQKms + \-- WQCKms + + * src/main/java/de/intevation/flys/artifacts/model/W.java: + New. Base class + + * src/main/java/de/intevation/flys/artifacts/model/WW.java: + New. Model for W~W + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQDay.java, + src/main/java/de/intevation/flys/artifacts/model/WQ.java, + src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: + Adjusted to follow the new class hierarchy. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Removed superfluous imports. + +2012-01-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties, + src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java: + i18n for ManualPointsFacets. + +2012-01-27 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 138: PDF output for calculations. + + * src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + Create the PDF data source and generate the PDF report output. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Add the PDF facet to state. Add export facets only once. + + * doc/conf/artifacts/winfo.xml: + Added PDF facet to state. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java: + Added new field type 'differences'. + + * doc/conf/jasper/wdifferences.jasper: + New. Template for w-differences PDF export. + +2012-01-27 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + New method that creates and returns the chosen differences of w-difference + calculation as string. + +2012-01-27 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 138: PDF output for calculations. + + * src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + Create the PDF data source and generate the PDF report output. + + * src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + doc/conf/artifacts/winfo.xml: + Added PDF facet to state. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java: + Added new field type 'day'. + + * doc/conf/jasper/duration.jasper: + New. Template for duration curve PDF report. + +2012-01-26 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 138: PDF output for calculations. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Create the PDF datasource and generate the PDF report output. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + doc/conf/artifacts/winfo.xml: + Added PDF facet to state. + + * doc/conf/jasper/computed-discharge.jasper: + New. Template for computed discharge PDF report. + +2012-01-26 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 138: PDF output for calculations. + + * pom.xml: New Dependency to net.sf.jasperreports/jasperreports and + org.codehaus.groovy/groovy-all. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Added methods for PDF generation. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Create the PDF data source and generate the PDF report output. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java: + New. Data source for jasper reports containing the waterlevel calculation + result. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Added facet for PDF export to state. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added PDF facet type. + + * src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java, + src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + Added stub for inherited abstract method. + + * doc/conf/artifacts/winfo.xml: + Added PDF facet to outputmode 'export'. + + * doc/conf/jasper, + doc/conf/jasper/waterlevel.jasper: + New. Folder for jasperreports templates and first template for + waterlevel report. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n string for calculation mode. + +2012-01-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Renderer 'manual' points in LongitudinalSectionGenerator. + + * pom.xml: New dependency to org.json/json. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + (doOut): Handle manual points. + (doPoints): Add point- series. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added MANUALPOINTS Facet Type. + + * doc/conf/themes.xml: Added Default Theme for Manual Points. + + * doc/conf/artifacts/winfo.xml: Added manual point facet to + compatibility list of longitudinal section diagram. + +2012-01-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java: + Removed obsolete imports. + +2012-01-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add initial infrastructure for user-provided data ('manual points'). + + * doc/conf/artifacts/manualpoints.xml: Trivial state model for new + Artifact. + + * doc/conf/conf.xml: Registered manualpoint artifact and factory. + + * src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java, + src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java, + src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java: + New. Basic infrastructure for ManualPoints. + +2012-01-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Removed superfluous condition checks. + +2012-01-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Cosmetics, documentation. + +2012-01-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Add states/transitions stubs for + "Bezugsllinenverfahren." + + * src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveInputState.java: + Stubs for the two new states. + +2012-01-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/visualize-transitions.xsl: Fixed output of the conditions + of the transitions. Now you can see the circumstances + when a branch is taken. + +2012-01-25 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 461. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Override buildChartSection() to disable the chart subtitle entry in + ChartSettings. + +2012-01-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + I18N for WINFO calculations messages. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Allow optional arguments in error messages to support meaningful + formatting containing e.g. numbers. + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Added a convenience getMsg() method. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation2.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation3.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Adjusted the code to use the I18N symbols now. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added the I18N strings. + +2012-01-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Handle the case in "W auf freier Strecke" where more than + one Q is related to a W. TODO: Generate user report. + +2012-01-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Added code for the simple case of "Bezugslinienverfahren" ("W auf freier Strecke"). + TODO: Handle case if the model returns more than one Q for a given W. + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Micro optimizations. + +2012-01-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue452 (Annotations at second y-axis). + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new type (duration_curve.mainvalues.q). + + * doc/conf/themes.xml: Added theme mapping for new facet type. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Create another Facet. + + * doc/conf/artifacts/winfo.xml: Added new facet type to compatibility + list. + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Handle new Facet. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Added field to be able to remember which axis to stick to. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java: + Tell Annotations to stick to Q axis in the special duration_curve + environment. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (AxisDataset): Added plotAxisIndex to now have a + two-way-association. + Tell own axisDatasets to which 'jfreechart'-axis they are assigned. + Evaluate which axis the StickyAxisAnnotations should be sticked to, + and calculate text and line positions accordingly. + Removed junk. + +2012-01-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix compilation. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java: + Use StickyAxisAnnotations instead of XYTextAnnotations. + +2012-01-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Some unification of Annotation handling. + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + Add a third annotation type (now have text, hyk and sticky). + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Use double instead of float values, removed commented code. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Reduced to keep information about placements etc only. Not a + Annotation (in JFreeChart sense) anymore. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Use StickyAxisAnnotations instead of XYTextAnnotations. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + Added new LineStyle class. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Call addAnnotationsToRenderer later, where positioning information + is already known. + (addAnnotationsToRenderer): Deal with the three Annotation types. + Instead of StickyAnnotations, add + CollisionFreeXYText- and + XYLineAnnotations. + (Area): Helper class. + +2012-01-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Some unification of Annotation handling. + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + +2012-01-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue395 (SVG/PDF-Export: Längsschitt enthält keine + Streckenfavoriten.) + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + Fix pdf/svg rendering of annotatios, by adding a + ChartRenderingInfo-object to the chart.draw call. + +2012-01-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Added new key and getter for a short subtitle. The short subtitle is + used if no range exists. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n string for shor subtitle. + +2012-01-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/ChartArtifact.java: + Removed state validation. Validation prevents drawing the diffenrences + diagramm and all states except of WDifferencesState always return + true. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + New. Candidate to replace StickyAxisAnnotation eventually. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Added null-guards to functions parameters. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: + Respect flowing direction of river when finding valid + hykformations. + +2012-01-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Add an empty facet to this state if the artifact is a Chartartifact. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Do not add the range to subtitle if no range exists. + +2012-01-20 Raimund Renkert <raimund.renkert@intevation.de> + + 'New chart' for cross sections. + + * doc/conf/artifacts/chart.xml: Updated the states and transitions for + new charts. + + * doc/conf/meta-data.xml: Added cross sections to datacage. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Changed cast from WINFOArtifact to FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/ChartArtifact.java: + Changed artifact data strings for chart_type. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Changed i18n string for cross sections and logitudinal sections. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add basic (text) styling for HYKs. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Minor cleanup, pass HYK theme on. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Apply TextStyle to TextAnnotation part for HYK zones. + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + (TextStyle): New class to bundle text-styling info. + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + Refactored constructors to ease setting Style in the newly + created usage scenario. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java: + Cleanup. Mark spot where State-based caching could happen. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java: + Cosmetics. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/cache.xml: Added Cache for HYKS. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: + Made HYKFactory.Zone Serializable. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java: + Cosmetics. + +2012-01-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added style definition for hyks. + + * doc/conf/themes.xml: Added hyk style (text). + +2012-01-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Removed cache "service-distanceinfo". + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Now uses the annotations from the LocationProvider and the + XML documents are no longer cached. + +2012-01-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Removed "annotations" cache. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Removed annotation caching. + + * src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java: + Changed internal data structure to FastAnnotations which are also cached. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java: + Use FastAnnotations now which are fetched via the LocationProvider. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Added + time measurement for writing the CVS output. + + * src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java: + Removed superfluous import. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Respect visibility flag of HYK facet. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Log malcondition, make colored hyk-box a bit smaller. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java, + src/main/java/de/intevation/flys/artifacts/model/DataFacet.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java, + src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Cosmetics, docs, improved logging. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Recommend hyks for current river if hit by + a crosssection-out. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Somewhat improved HYK handling and rendering. + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java: + Store ids in more sensibly named data item and expose it. + Spawn all facets in inactive state. + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: + Make HYK name accessible, do not query hyks by river, but by hyk-id, + made query more real-world. + + * src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java: + Use hyks name as facet name, pass hyk-id when asking for hyks. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Somewhat improved HYK handling and rendering. + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + Added ability to store 'zones', next to text annotations. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (getLowestYValue, getUppestYValue, colorForHYKZone), + (addBoxAnnotations): New. Create box annotations from zones. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + (doHYK): New, handle hyk facets by adding zones to annotation + container. + +2012-01-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Preparing improved HYK handling. + + * src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: + (Zone.getTo): New accesor. + TODOs and documentation added. + +2012-01-18 Raimund Renkert <raimund.renkert@intevation.de> + + 'New Chart' for w-differences curve. + + * doc/conf/artifacts/chart.xml: Added empty facet to output mode. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Add an empty facet if the artifact is a ChartArtifact. + +2012-01-18 Raimund Renkert <raimund.renkert@intevation.de> + + 'New Chart' for discharge longitudinal section curve. + + * doc/conf/artifacts/chart.xml: Added transition for location input. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Changed cast from WINFOArtifact to FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + Add an empty facet if the artifact is a ChartArtifact. + +2012-01-18 Raimund Renkert <raimund.renkert@intevation.de> + + 'New Chart' for duration curve. + + * doc/conf/artifacts/chart.xml: Added state and transition for location input. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Changed cast from WINFOArtifact to FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java: + Add an empty facet if the artifact is a ChartArtifact. + +2012-01-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added accidentally ommitted HYKFacet, fixing build. + + * src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java: + New, stubby facet for hyk infrastructure. + +2012-01-18 Raimund Renkert <raimund.renkert@intevation.de> + + 'New Chart' for computed discharge curve. + + * doc/conf/artifacts/chart.xml: Fixed transitions and added state for km input. + + * src/main/java/de/intevation/flys/artifacts/model/EmptyFacet.java: + New. Added an empty facet to avoid deleting an empty output. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java, + src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + Changed some return values if the artifact is a ChartArtifact. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Changed casts from WINFOArtifact to FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java: + Add an empty facet if the artifact is a ChartArtifact. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Set a default axis range if the range is null. + +2012-01-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added stub hyk infrastructure. + + * doc/conf/artifacts/hyk.xml: Added trivial transition configuration + for hyk artifacts. + + * doc/conf/conf.xml: Register HYK artifact and its transition conf. + + * src/main/java/de/intevation/flys/artifacts/HYKArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java, + src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java: + Added static 'hyk' artifact, facet and state. + +2012-01-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Add 'hyk' facet type. + +2012-01-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add hyk facet to compatibility list of winfo.xml . + + * doc/conf/artifacts/winfo.xml: Add hyk facets to compatibility list. + +2012-01-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method getDataAsLong that returns a Long representation of a data item or + null if no such data item is existing or it cannot be parsed as Long. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function + that returns the selected reference gauge (specified by 'reference_gauge' + parameter) of a FLYSArtifact. + +2012-01-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java: + Cache a TreeMap<km, annotation string> of the annotation values of whole + rivers. This is _much_ more efficient than firing an HQL/SQL statement for + each km and caching these results. + +2012-01-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java: + Deleted. It is in the backend now. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionChunk.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLineFactory.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java, + src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Adjusted to use the fast cross section line from backend now. + + * doc/conf/cache.xml: Store cross section lines cache on disk. + + * src/main/java/de/intevation/flys/artifacts/states/StaticWQKmsState.java, + src/main/java/de/intevation/flys/artifacts/model/DataFacet.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: Removed + superfluous imports. + +2012-01-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix assignment of stateId/hash in WaterlevelFacet. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + More verbose logging, fix hash/stateid assignment. + + * src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + (deepCopy): implemented. + +2012-01-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + "Ported" StaticWQKmsArtifact to use compute-type caching mechanism. + + * doc/conf/artifacts/staticwqkms.xml: Declare trivial info. + + * doc/conf/conf.xml: Register staticwqkms artifact and factory. + + * src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java: + Sublacss DataFacet. + + * src/main/java/de/intevation/flys/artifacts/states/StaticWQKmsState.java: + New. State. + + * src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java: + Refactored. Most computation and stuff now done in State and Facet. + +2012-01-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Minor cosmetics. + +2012-01-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactoring. + + * src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + Added new constructor. + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: + Refactored, subclass BlackboardDataFacet. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Refactored, subclass DataFacet. + + * src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java: + Adjusted. + +2012-01-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: + Cosmetics, added new constructor. + +2012-01-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Use improved caching for cross section data. + !!! This commit needs heavy testing !!! + + * src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java: + Refactored to provide the map to determine the nearest cross section line + neighbors for a given km to the public. This is a bit hackish because + it hhould have its own factory which is then used by this service and + other parts of the code. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + searchCrossSectionLine() now returns a FastCrossSectionLine. To find this + line efficiently it uses the map of the CrossSectionKMService which + already provides a nearest neighbor searching mechanism for cross + section lines. The FastCrossSectionLine is fetched with the + FastCrossSectionLineFactory which uses a cache as described in the + previous commit. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Uses + the FastCrossSectionLine instead of CrossSectionLines now. + + * src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java: + Added method fetchCrossSectionProfile() to access the point data in + the profile generating compatible way. + + * src/main/java/de/intevation/flys/artifacts/ChartArtifact.java: Removed + superfluous import. + +2012-01-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Added cache for fast section lines chunks. + + * src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionChunk.java: + New. Chunks of FastCrossSectionLines. Stores cross section lines for ranges + of one KM. + + * src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLineFactory.java: + New. Access fast cross section lines. It uses the cache 'fast-cross-section-lines' + configured in cache.xml to store chunks of cross section lines. + + * src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java: + New. Stores the important data (points) of a cross section line. + +2012-01-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Added a new calculation option for historical discharge curves. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translations for + historical discharge curves. + +2012-01-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added certain facets to to + compatibility matrices. + +2012-01-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/annotation.xml: Fixed accidental change. + +2012-01-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/annotation.xml: Cosmetics. + +2012-01-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Enabled old floodmap calculations for output + type 'map'. + +2012-01-13 Raimund Renkert <raimund.renkert@intevation.de> + + Initial implementation for module 'new chart'. + + * src/main/java/de/intevation/flys/artifacts/ChartArtifact.java: + New. Artifact for module 'new chart'. + + * doc/conf/artifacts/chart.xml: + New. Artifact description for the new artifact. + + * doc/conf/conf.xml: + Added new artifact to config. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for 'new chart' chart types. + +2011-01-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Cosmetics. + +2011-01-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Avoid NPE when copying data from one artifact to another. + +2011-01-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (expandRange): Prevent collapse due to negative values. + +2012-01-12 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/artifacts/map.xml, + doc/conf/conf.xml, + src/main/java/de/intevation/flys/artifacts/MapArtifact.java: + Changed the MapArtifact name to 'new_map'. + +2011-01-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Added code to calculate the area of the generated polygons. + TODO: Render the generated area sum to the plot. + +2011-01-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Replaced System.err.println()s with proper logging. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed + superfluous imports. + +2011-01-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue450 (i18n: Datenkorb: longitudinal-section) + + * doc/conf/meta-data.xml: Replaced dash by underscore in + longitudinal-section. + +2011-01-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Towards areas on other than the first axes. + + * src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + Changed signature on which to provide data via the blackboard. + Include facets name to allow unique identification. + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java: + Store name of one of the facets involved in area creation. + (AreaFacet.Data): New class to hold result data. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + New methods to find out whether we have a general Q or W type of + facet. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + (doArea): Use new Result-Data object instead of Object[], resolve + which axis to put area to. + (axisIdxForFacet): New. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Subclass LongitudinalSectionGenerator. + +2011-01-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java: + Do not intefere with CrossSections. + +2011-01-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, cleanups. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + (getCrossSections, getCrossSectionNames): Removed. + +2011-01-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue439 (Streckenfavoriten lassen sich nicht über den Datenkorb + hinzuladen) + + * doc/conf/meta-data.xml: Made Annotations available via datacage + in longitudinal section, cosmetics. + +2012-01-11 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/conf.xml: + Added output generator for output type 'map'. + + * doc/conf/artifacts/map.xml: + Changed output name to 'map'. + + * doc/conf/meta-data.xml: + Added new output type 'map'. + +2011-01-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue446 (Dauerline/Abflusskurve am Pegel: Eigenschaften vom + Hauptwertthema nicht aufrufbar) + + * doc/conf/themes.xml: Add default styles for mainvalues.q/w and other + themes. + +2012-01-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java: + Removed XPath injection security hole. A serious one because it allowed + inspecting the conf.xml file ... with all the db passwords. + +2012-01-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Removed superfluous imports. + +2012-01-11 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Added the definition of old calculation results + for floodmaps. + +2012-01-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: Added + methods getLayers() and removeLayer(). + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method getFacets() which returns a list of Facets supported by this + Artifact. In addition, the FLYSArtifact is now more verbose while + filtering Facets for Outputs. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Implemented initialize() which now copies the shapefile directory of the + model Artifact and modifies its Facets (adapts the shapepath which is the + uuid of the Artifact). + +2012-01-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/collections/OutputParser.java: Made + them more verbose for better debugging. + +2012-01-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Initialize() now also calls State.initialize() for each State. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Override initialize() which is defined in AbstractState. NOTE: Currently, + this method has no code. + +2012-01-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java: + New. The service to invalidate the caches. (Argh! Forgot to 'svn add') + +2012-01-06 Ingo Weinzierl <ingo@intevation.de> + + flys/issue298 (Karte: Automatischer Zoom auf Berechnungsergebnisse) + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Added a + debug statement that prints out the WSPLGEN extent. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Create new + Envelope instances for initial and max extent if they are not existing. + Some debug statements have now been removed. + +2011-01-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add cache for 'static' wqkms (e.g. BaseData) to default cache conf. + + * doc/conf/cache.xml: Add Cache Config for static wqkms. + + * src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java: + Adjust typo in cache name, minor cosmetic. + +2011-01-06 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MapArtifact.java: + The map artifact has two states now and overrides describe() to + generate UI sections in the describe response. + The map state overrides computeAdvance() instead of computeFeed(). + + * src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: + Changed the WMSDBArtifact in WMSDBState to FLYSArtifact and adjusted + constructors in state classes. + + * doc/conf/artifacts/map.xml: + Added initial state and transition. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added i18n strings for new state. + +2011-01-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix for flys/issue437 (Querprofil: Zugeladene Basisdaten + ignorieren W/Q-heit, falsche Namen). + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Set name also for first column (zero based). + +2012-01-06 Ingo Weinzierl <ingo@intevation.de> + + flys/issue196 (i18n/l10n: Zahlenformate einheitlich) + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java: New method + getRawValue() that extracts the raw double value from 'name' parameter. + + * src/main/java/de/intevation/flys/utils/Formatter.java: New method + getRawFormatter() that returns a NumberFormat instance for the current + locale. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Localized the W/Q labels in CSV exports. + +2011-01-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue442 (i18n: Datenkorb: flood-protections) + + * doc/conf/meta-data.xml: Replaced dash in flood-protection by + underscore to allow translation. + +2011-01-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue438 (i18n: Datenkorb: additionals) + + * doc/conf/meta-data.xml: Fix typo. + +2011-01-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java: + New. Uses the CacheFactory to invalidate caches by their names. + This can be used by external ETL processes like the AFT/DIPS importer + to prevent cache inconsistencies. + + Input documents look like this: + + <caches> + <cache name="my-cache"/> + ... + <cache name="your-cache"/> + </caches> + + Output documents look like this: + + <caches> + <cache name="my-cache">All elements removed.</cache> + ... + <cache name="your-cache">Error: Cache not found.</cache> + </caches> + + * doc/conf/conf.xml: Added the cache invalidation service. + + * src/main/java/de/intevation/flys/artifacts/services/FLYSService.java: + Added Override annotation. + +2011-01-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue432 (Diagrammeigenschaften/Flächenrenderer: + Legenden-schriftgröße für Flächenthemen wird ignoriert) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Respect legend item size when generating legend items for + area dataseries. + +2011-12-09 Raimund Renkert <raimund.renkert@intevation.de> + + Implemented new module "new map". + + * src/main/java/de/intevation/flys/artifacts/MapArtifact.java: + New. Artifact for the new module, extends RiverAxisArtifact and + contains the MapState class. + + * src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: + Added empty constructor to embedded state classes to allow instantiation + of MapState that extends the RiverAxisState. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: + Do not generate an initialExtent element if the initial extent is + empty. + + * doc/conf/artifacts/map.xml: + New. Describes the state for the new module. + + * doc/conf/conf.xml: + Added new config file. + +2012-01-05 Ingo Weinzierl <ingo@intevation.de> + + flys/issue444 (error_no_export_found bei "W bei ungleichwertigem Abfluss") + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: If no boolean + value "wq_free" exists in getWQMode(), false is the default. + +2011-01-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue443 (Querprofile: Hibernate LazyInitializationException) + + * doc/conf/cache.xml: Disable cache for cross-sections. + +2012-01-05 Ingo Weinzierl <ingo@intevation.de> + + flys/issue447 (W-Differenzen: Fehler beim Hinzufügen einer Parameterisierung) + + * src/main/java/de/intevation/flys/collections/CollectionAttribute.java: + Added a new method cleanEmptyOutputs() which removes Outputs that have + no Facets set. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: Call + CollectionAttribute.cleanEmptyOutputs() at the end of write() to remove + empty Outputs that have been added during the merge process. + +2012-01-05 Ingo Weinzierl <ingo@intevation.de> + + flys/issue440 (Karte: WSPLGEN Berechnungen für Mosel schlagen fehl) + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Modified the + getRiverBoundary() method because the signature of + RiverAxis.getRiverAxis() has changed. This method will now take each + geometry into account, that is retrieved by + RiverAxis.getRiverBoundary(). + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java: + Use GeometryUtils.getRiverBoundary() to determine the boundary of a + river. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Create the riveraxis shapefile with all geometries returned by + RiverAxis.getRiverAxis(). + +2012-01-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Repaired + broken items in legend. The new renderer requires the current plot. This + is set now. + +2012-01-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added a new field 'pointsize' to the virtual theme + 'HiddenColorLines'. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added methods to + parse the new field of 'HiddenColorLines'. + + * src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: Apply the + pointsize defined in themes. + +2012-01-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Use correct keys for buffering in getMinimum() and getMaximum(). + +2012-01-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java, + src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java: + Moved to de.intevation.flys.jfree. + + * src/main/java/de/intevation/flys/jfree/StyledXYSeries.java, + src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Moved from de.intevation.flys.exports. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Added necessary imports. + +2012-01-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java: + Buffered the computation results of getMinimum() and getMaximum(). + +2012-01-04 Ingo Weinzierl <ingo@intevation.de> + + flys/issue393 (Themenstileditor: Minimum anzeigen / Beschriftung anzeigen) + + * src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java: + New renderer that overrides JFreeChart's XYLineAndShapeRenderer. This + renderer brings the option to explicitly display the minimum and/or + maximum or a series as shape. Currently, there are no options to adjust + the style of those shapes. + + * doc/conf/themes.xml: Added a new virtual theme 'MinMaxPoints'. All line + theme inherit from that theme now. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added methods to + parse the fields 'showminimum' and 'showmaximum' of 'MinMaxPoints' theme. + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: Added + methods to apply the fields of the new Theme 'MinMaxPoints'. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Modified + the getRenderer() method which now always returns a new instance of + EnhancedLineAndShapeRenderer. + +2011-01-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow styling of outline of areas. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Allow styling of outline of areas. + + * src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java: + Parse outline style for areas, apply it to renderer. + +2012-01-03 Ingo Weinzierl <ingo@intevation.de> + + flys/issue104 (W-INFO: Wasserspiegellagenberechnung / Strecke) + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: Call + the new flys-backend method Wst.determineMinMaxQFree() to determine the + min/max Qs at a given kilometer. + +2011-01-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Reflect name chnage of longitudinal sections + area artifacts and include ColorLine style for area styles. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + flys/issue370 (WINFO: Berechnungsausgabe W/Pegel [cm] fehlt bei Wasserspiegellage und W am Pegel) + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: New method that + extracts the double value of a WQ object's name. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Adapted + the header of CSV exports and the content of the "W at gauge" column. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Adapted method signatures that have been changed in WaterlevelExporter. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings used in the CSV + export. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Check + if the location of a CSV row is in range of the reference gauge. Write + "outside reference gauge" into CSV in such cases. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + PART II of flys/issue125 (W-INFO: Wasserspiegellagenberechnung / tabellarische Berechnungsausgabe) + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Add the + named main value of a Q and the name of the gauge used for the calculation + if the WQ mode is "W at gauge" or "Q at gauge". + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Adapted the method signatures that have been modified in + WaterlevelExporter. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/AxisSection.java, + src/main/java/de/intevation/flys/exports/ExportSection.java, + src/main/java/de/intevation/flys/exports/LegendSection.java, + src/main/java/de/intevation/flys/exports/ChartSection.java: Removed + unused imports. + +2012-01-02 Ingo Weinzierl <ingo@intevation.de> + + PART I of flys/issue125 (W-INFO: Wasserspiegellagenberechnung / tabellarische Berechnungsausgabe) + + * doc/conf/cache.xml: Registered a new Cache for the LocationProvider. + + * src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java: + New. This class is able to return the description of a location based on a + river and kilometer parameter. The LocationProvider stores single + locations into a Cache if one is configured for this class. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + Added a method that returns a single Annotation for a specific kilometer and + river. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a method + getLocationDescription() that might be used to determine the description + of a specified kilometer for a given river. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Make use + of FLYSUtils.getLocationDescription() to add a new column that contains + the location description. + +2011-12-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: Write + min/max values for free Qs into Artifact's DESCRIBE document. + +2011-12-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: Fixed + broken order to determine the step width of Qs and Ws. + +2011-12-28 Ingo Weinzierl <ingo@intevation.de> + + flys/issue104 (W-INFO: Wasserspiegellagenberechnung / Strecke) + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Validate user defined free Q values. + +2011-12-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Compute better step width based on a maximal number of steps = 30. + Results with digits are rounded up. E.g.: + Q range = 9.6 - 1750 + Step width = 58.01 + Rounded result = 60 + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/AxisSection.java, + src/main/java/de/intevation/flys/exports/LegendSection.java, + src/main/java/de/intevation/flys/exports/ChartSection.java: Subclasses + TypeSection to be able to use convinience methods for string, integer, + double and boolean values. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: The + getSize() method now returns null if no width and height is specified in + the request document or if width/height <= 0. It no longer returns the + result of getDefaultSize(). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Set the + size of a chart export to the size specified in the ChartSettings if + there are no valid values in the request document. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: Set the + chart size to ChartGenerator.getDefaultSize() if no valid values are + returned by ChartGenerator.getSize(). This has been done autoamtically + before. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/TypeSection.java: New. This + Section defines some convinience methods to add/set string, integer, + double and boolean values. + + * src/main/java/de/intevation/flys/exports/ExportSection.java: New. + Subclasses TypeSection. The ExportSection currently offers attributes + 'width' and 'height'. + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: Added + getter/setter methods to support an ExportSection. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Create an + ExportSection while initial ChartSettings creation. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added and + make use of a new method createLegendLabelFont() to create unified Fonts for + LegendItems. This method considers the user defined size for LegendItems. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Implemented adjustAxes(). This method now sets the label Font of the X + axis. Its size is determined by getXAxisLabelFontSize(). + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/AxisSection.java: Added method + getFontSize() to retrieve the font size for an axis. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Modified createYAxis(int): call super.createYAxis(int) and adjust + necessary settings - no Axis creation takes place here. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added + getXAxisLabelFontSize() and getYAxisLabelFontSize(int) to retrieve the + user defined font size for an axis. The getYAxisLabelFontSize() is used in + createYAxis(int) to set the font size for axes labels. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Override getYAxisWalker(). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Create new + instances of IdentifiableNumberAxis in createYAxis(int) default + implementation. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/AxisSection.java: Added + getLabel() to retrieve the axis label. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Override getDefaultXAxisLabel() and getDefaultYAxisLabel() defined in + XYChartGenerator. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Implement + getXAxisLabel() and getYAxisLabel(int). Both methods search for an axis + label defined in the ChartSettings first. If no label is specified or if + no ChartSettings is set, getDefaultXAxisLabel() or + getDefaultYAxisLabel(int) is called to retrieve the initial/default axis + label. + +2011-12-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: Modified the + signature of addAxisSection(). This method now accepts AxisSections only. + In addition, there is a new method getAxisSection(String) that returns an + AxisSection specified by its identifier. + + * src/main/java/de/intevation/flys/exports/AxisSection.java: Added new + methods getIdentifier(), isFixed(), getUpperRange() and getLowerRange() to + retrieve the attributes supported by this Section. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Make use + of axes ranges specified in ChartSettings if an axis is fixed. + +2011-12-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/IdentifiableNumberAxis.java: New. + Subclasses JFreeChart's NumberAxis and offers a getId() method which + returns an identifiable key. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Implements + a createNumberAxis() method that should be used by all subclasses to + create new axes. This method returns an instance of IdentifiableNumberAxis + which is required for zooming. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Create new NumberAxis instances by using XYChartGenerator.createNumberAxis(). + +2011-12-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Implemented the methods getChartTitle() and getChartSubtitle(). Both + methods try to get the required information from ChartSettings. If no + ChartSettings is set for this OutGenerator, these methods will call + getDefaultChartTitle() and getDefaultChartSubtitle(). + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Renamed getChartTitle() and getChartSubtitle() to + getDefaultChartTitle() and getDefaultChartSubtitle(). In addition, the + methods addSubtitles() became more robust - these OutGenerators add + subtitles only if the subtitle is not empty. + +2011-12-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: Added a + setSettings(Settings) method. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Call OutGenerator.setSettings() before calling doOut() for each Facet. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Implemented + setSettings() and added convinience methods to access chart specific + settings. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/ReportGenerator.java: Implemented + setSettings(). + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Make use + of the attributes specified in the Settings: the title, subtitle, + displayGrid and displayLegend settings are functional now. + +2011-12-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartSettings.java, + src/main/java/de/intevation/flys/exports/LegendSection.java, + src/main/java/de/intevation/flys/exports/ChartSection.java: Use more + concrete classes than Settings and Section in these classes to avoid a lot + of castings. + +2011-12-22 Ingo Weinzierl <ingo@intevation.de> + + flys/issue242 (W-INFO: Fehlende Header in Datenexporten) + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added functions + getQs(), getWs(), getGauge(), getGaugename() and getRivername() that all + take a parameter FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Moved the + implementation of getGauge() to FLYSUtils. The getGauge() in this class + just calls and returns FLYSUtils.getGauge(). + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Write a + header into a CSV export containing meta information about this export. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings used in the CSV + export as header. + +2011-12-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + (getKm): Removed, not called anymore. + +2011-12-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Include km of cross-section-master in diagrams subtitle (fetched + from 'blackboard'. + +2011-12-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: + Cosmetics, docs. + +2011-12-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java + (getInitialFacetActivity): Only newest CrossSection is initially + active. + +2011-12-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java + (isNewest): New, query whether a CrossSection is the newest for its + river, doc. + +2011-12-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + convinience method to retrieve the value of an data object stored at + FLYSArtifact as Boolean value. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a method that + returns the named value of a given double value. This method returns only + the named value, if the WQ mode is "Q at gauge" and if the value fits to a + named value. In addition to this method, there is a new method to retrieve + the selected WQ mode as 'WQ_MODE' enum. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Removed prepareData() and its call. The data preparation had a bad side + effect: the modifications are "persisted" into cache, which has again bad + side effects. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Removed + prepareData(). The label creation for columns in the WST export will now + take place in addWSTColumn(). With help of the master Artifact (I forgot + this Artifact in my last commit) we are able to replace Q values with + their named main value. + +2011-12-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Cover 'locations' case for initial km of cross section artifacts. + +2011-12-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + (initialize): Eat ld_from from master artifact. + (setup): Set cross_section.km to either masters km or the lowest + defined cross-section line, whatever is bigger. + +2011-12-21 Ingo Weinzierl <ingo@intevation.de> + + flys/issue252 (W-INFO: Wasserspiegellagenberechnung / Mitführung der Jährlichkeiten in der Diagramm-/Ergbnisausgabe) + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function + stripNamedMainValue(). The result of this function is a named main value's + base name without declaration of a year. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: Added a + method pepareData() that is called in doOut() before the data supported by + the current Facet is added using addData(). + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Override + the prepareData() method to reset the name of WQKms objects. The Qs in a + waterlevel export should be the Q value or the named main value if the + value fits to a named main value. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Survive cases where the first dataset has an area-renderer assigned. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/AreaArtifact.java: + Store additional parameter (whether or not to fill everything in + between two curves.) + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java: + Deliver additional info from artifact. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Evaluate new parameter. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Add transparency setting to area theme style. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Helper to + access transparency setting in theme. + + * src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java: + Respect transparency setting. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java: + Subclass BlackboardDataFacet to provide data for area calculation. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Cast data to WKms instead of WQKms. + +2011-12-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Use a ';' as seperator between Qs and Ws. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java + (doOut, doArea): Added handling for areafacets. Code yet mostly + copied from CrossSectionGenerator. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Refactoring, subclass BlackboardDataFacet, remove duplicate code. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * doc/conf/artifacts/winfo.xml, + src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Renamed facet for consistency reasons. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Make Waterlevelfacet deliver data via blackbord. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Subclass BlackboardDataFacet. + +2011-12-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Create all formatted string labels for Ws and Qs in this class, because + this class is the only instance that knows that there are double values + to format. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Introduced new Facet that will deliver whatever getData returns via + blackbord under key which is defined by convention. Attention, the + data is not cached if handled this way. + + * src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java: + New facet, will be useful for easing implementation of facets that + can contribute to area-computations. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/VisibleAttribute.java: + Removed obsolete imports. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Removed obsolete imports. + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java, + src/main/java/de/intevation/flys/artifacts/AreaArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/AreaCreationState.java, + src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Removed obsolete imports. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + With StableXYDifferenceRenderer, create legend items in rectangular + form, to discern "line" from "area" in legend. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java + (legendLine, legendShape): Renamed. + (getLegendItem): Create LegendItem with fill, use PositivePaint for + that. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added further 'area' infrastructure. + + * src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java: + New, "area dataset". + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + (doOut): Use helper to decide if facet is an 'area' facet. + (doArea): Construct StyledAreaSeriesCollection instead of two + dataseries. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (AxisDataset.isArea): Distinguish area datasets with instanceof. + (AxisDataset.addArea): New. Replaces addAreaDataset. + (addAreaSeries): Simplified with new custom SeriesCollection. + (applyTheme): Register and style StableXYDifferenceRenderer for + StyledAreaSeriesCollections. + Added various TODOs and debug output to stabilize development. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added facets to compatibility + matrices. + + * doc/conf/themes.xml: Added Area theme defaults. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Lay ground for having areas in longitudinal section diagrams, too. + This is done by different naming of the facets. + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java: + Make the name dynamic. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added further facet types, helper. + + * src/main/java/de/intevation/flys/artifacts/AreaArtifact.java: + Store name for facets in data item, restrict access to some fields. + + * src/main/java/de/intevation/flys/artifacts/states/AreaCreationState.java: + Use AreaArtifacts data item to use name for facets. + +2011-12-20 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Doc. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Whitespace. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Doc and + whitespace. + +2011-12-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java + (parseBoolean): New, extracted, updated callers. + (parseFillColorField, parseShowBorder): New, for area styles. + +2011-12-19 Ingo Weinzierl <ingo@intevation.de> + + flys/issue202 (W-INFo: Wasserspiegellagenberechnung / Vorbelegung Strecke) + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added a system property which is used to determine, if the DESCRIBE + document of an Artifact should include default values (values, that have + been inserted by the user some time ago) or not. The default case is, + that the DESCRIBE does NOT include default values. To enable default + values, set "flys.use.default.values" to "true". + +2011-12-19 Ingo Weinzierl <ingo@intevation.de> + + flys/issue419 (Themen-Name "Q(null)" bei W bei ungl. A.) + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + Use correct variable to create Facet names. + +2011-12-19 Ingo Weinzierl <ingo@intevation.de> + + flys/issue380 (W-INFO / Überschwemmungskarte, falsches DGM) + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + convinience method that returns a parameter of FLYSArtifact as Integer. + + * src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java: Override + validate() to determine, if the DGM selected by the user is valid for the + current calculation range and river. + +2011-12-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Roll-back accidentally committed changes. + +2011-12-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java + (doOut): Hide 'invisible' (deleted) themes from Outgenerators. + +2011-12-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added area.name data item and access to areaartifact. + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java: + Rephrased debug output, do survive case where only one curve is + given for area calculation (this is the "above" or "under" case). + + * src/main/java/de/intevation/flys/artifacts/AreaArtifact.java + (getAreaName): Access "area.name" data item. + + * src/main/java/de/intevation/flys/artifacts/states/AreaCreationState.java: + Respect area.name data of artifact when reproducing facets. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Fix, accidentally added wrong factory in last + commit. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Register area artifact factory. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added area artifacts to cross-section + compatibility matrix. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add area dataseries when facet delivering one. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java + (doOut): Handle area facets. + (doArea): Register areas for area facets. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add simple area registerig functions. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (AxisDataset.addAreaDataset): New, add an area dataset. + (AxisDataset.isArea): New. + (addAreaSeries): New. Add Area Dataset. + (applyThemes): Pass info if we have an area, to set different + renderer. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StaticState.java: + Added convenience function and easy sybclassing. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Register AREA ("area") facet type. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Register blackboard key uuid+index and respond with data to it, as + assumed by the areaartifact and facet. + +2011-12-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added partial area-infrastructure. + + * src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java, + src/main/java/de/intevation/flys/artifacts/AreaArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/AreaCreationState.java: + New artifact, facet and state for area rendering. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Defined an + interface YAxisWalker that allows to walk over each Y axis definition in + subclasses. This walker can be retrieved using the new getYAxisWalker() + method. The AxisSections are built in this class now. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Implemented the YAxisWalker interface and the getYAxisWalker() method. + Removed the code to build AxisSections. + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Implemented getYAxisLabel(int pos) and getYAxisWalker(). + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Implemented the getYAxisWalker() method. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Some optimizations during out() operation - the CollectionAttribute is + parsed a single time now (*i guess*). This code really needs some + refactoring! + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added an INFO message that displays the duration time for the out() + operation. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Calls super.buildAxisSections(). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Implemented the method buildAxisSections(). The result list will contain + an AxisSection for the X axis. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: Bugfix: + Add new Outputs to the current CollectionAttribute if no old one is + existing. + +2011-12-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Directly fetch key/value pairs when writing a collection attribute. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: Added new + functions that allow parsing a ChartSettings object from DOM Node. + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: Parse + the Settings of each Output. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/CollectionAttribute.java: + Added a method to set a new Settings object for a specific Output and a + method to clear the list of Facets of a specific Output. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: The + AttributeWriter no longer creates new CollectionAttributes - it only + modifies the old CollectionAttribute. At first, it clears the Facets of + all Outputs. Finally, the merged Facets are added to the Outputs. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added the CollectionAttribute to the AttributeWriters constructor. + +2011-12-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DoubleAttribute.java: New. An + Attribute that stores double values. + + * src/main/java/de/intevation/flys/exports/AxisSection.java: Added methods + to set values for 'fixation', 'font-size', 'lower' and 'upper'. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Set new attributes mentioned above for each axis' AxisSection. + +2011-12-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/AxisSection.java: Added methods + to set the axis label and id. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Improved + the ChartSettings that will now contain a set of AxisSections. The new + buildAxisSections() method in this class is not implemented and needs to + be implemented by subclasses. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Override buildAxisSections() of XYChartGenerator to create an AxisSection + for each axis that is able to be displayed in this sort of chart. In + addition, there is a new method getYAxisLabel(int) that returns the label + for a specific Y axis. + +2011-12-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/IntegerAttribute.java: New. + Concrete subclass of a DefaultAttribute for storing integer values. + + * src/main/java/de/intevation/flys/exports/LegendSection.java: New. A + concrete Section subclass to store legend specific attributes. + + * src/main/java/de/intevation/flys/exports/BooleanAttribute.java, + src/main/java/de/intevation/flys/exports/StringAttribute.java: Removed + needless import of org.w3c.dom.Attr. + + * src/main/java/de/intevation/flys/exports/ChartSettings.java: ChartSettings + is able to store a Section for legends now. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added + methods to retrieve the font size of legends and if the legend should be + visible or not. In addition, the ChartSettings returned by this instance + will now contain a LegendSection as well. + +2011-12-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Introduced + methods getChartSubtitle() and isGridVisible(). getChartSubtitle() returns + in this implementation null. Concrete subclasses should override this + mehtod if they require subtitles in charts. isGridVisible() determines if + the grid in the chart should be visible or not. This method return always + true in this implementation. + In addition, the Settings object returned by getSettings() will now have a + ChartSection set properly. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Override getChartSubtitle(). + +2011-12-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Prepare the OutGenerator (process each of the Output's Facets) during the + describe() operation to be able to return an initial Settings object. + +2011-12-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/BooleanAttribute.java, + src/main/java/de/intevation/flys/exports/VisibleAttribute.java, + src/main/java/de/intevation/flys/exports/StringAttribute.java: Fixed wrong + usage of DOM operations. + +2011-12-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/BooleanAttribute.java, + src/main/java/de/intevation/flys/exports/VisibleAttribute.java, + src/main/java/de/intevation/flys/exports/StringAttribute.java: New. + Concrete subclasses of a DefaultAttribute. + + * src/main/java/de/intevation/flys/exports/ChartSettings.java, + src/main/java/de/intevation/flys/exports/AxisSection.java, + src/main/java/de/intevation/flys/exports/ChartSection.java: + Implementations for chart settings. WORK IN PROGRESS! + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Override + the getSettings() method. The implementation here returns a ChartSettings + instance. + + * src/main/java/de/intevation/flys/exports/EmptySettings.java: Modified the + node name of the settings ("art:settings" -> "settings"). + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Cosmetics, doc. + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Remove needless imports. + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix/Guard certain misconditions. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Do + not crash when given null-range. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Do not crash when given malformed array. + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java, + ChangeLog: Whitespace cosmetic. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Annotation cosmetic. + + * src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java: + Convenience cosmetic. + + * src/main/java/de/intevation/flys/utils/DataUtil.java: + vim-magicosmetic. + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Implement new WaterLineArtifact where needed so far. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Declare that we implement WaterLineArtifact. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + (getWaterLines): Implement to fulfil new WaterLineArtifact- + interface-impl. Also generate new Facet. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Do not depend on WINFOArtifacts, but on WaterLineArtifacts instead. + +2011-12-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added interface WaterLineArtifact to be implemented by artifacts + that know how to create a water line "against" a cross section. + + * src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java: + New, straight-forward interface. + +2011-12-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/EmptySettings.java: An + implementation of the Settings interface defined in the artifact-database + module. This implementation accepts no Section objects at all and creates + an empty "settings" Node in its toXML() operation. + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: Defined a new + method getSettings() that returns a Settings instance. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ReportGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Implemented the getSettings() operation. All OutGenerators will currently + return an instance of EmptySettings. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Before the DESCRIBE document is created, we gonna evaluate each Output + defined in the Collection's attribute document, if it has a Settings + object set. If this is not the case, the relevant OutGenerator is called + to retrieve a new instance of Settings. + + * src/main/java/de/intevation/flys/collections/CollectionAttribute.java: + Append the Settings of Outputs to the Output nodes in the XML + representation. + +2011-12-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Recommend cross-sections. + + * doc/conf/meta-data.xml: When having a cross-section out, recommend + respective artifacts. + +2011-12-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Register factory for CrossSectionArtifacts. + + * doc/conf/conf.xml: Register CrossSectionArtifact-Factory. + +2011-12-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/CollectionAttribute.java: + New. This class will store the information provided in the Collection's + attribute (which is a DOM document). + + * src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java: + Store an instance of CollectionAttribute and append its XML representation + to the DESCRIBE document. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: Removed + all DOM operations from this writer. Its new task is to create a new + CollectionAttribute object which represents a merged version of the old + CollectionAttribute and the information provided by the Collection's child + Artifacts. + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: The + result of AttributeParser's parse() operation is a CollectionAttribute + object now. The methods getOuts() and getFacets() are as of now proxy + methods that call the relevant methods of CollectionAttribute. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Some structural changes in the process to build the attribute Document of + the Collection's DESCRIBE. We will no longer work with Document during + this process but with instances of CollectionAttribute. + +2011-12-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Server-side of newer Cross-Section diagram construction architecture. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (searchCrossSectionKmLine, getCrossSectionSnapKm), + (getCrossSectionData): Removed, most functionality contained in + CrossSectionArtifact. + (getWaterLines): Now get CrossSectionLines to calculate water line. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Get a CrossSectionLine from blackboard. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Hard TODO, commented out function needed for subtitle to allow + compilation. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Added Empty-Dataset- guard. + +2011-12-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Cosmetics. + +2011-12-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java, + src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Removed superfluous imports. + +2011-12-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java: + New. This class helps generating the DESCRIBE document of a collection. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Moved some of the code to create the DESCRIBE document out to + CollectionDescriptionHelper. + +2011-12-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Resolve todo about wrongly named cross sections. + Open StaticState to allow that facets survive a compute. + + * src/main/java/de/intevation/flys/artifacts/states/StaticState.java + (computeAdvance, computeFeed, computeInit): Override to call + staticCompute. + (staticCompute): New. Do nothing but be able to be overridden. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java + (setup): Fetch facets name from db (resolves todo). + (getCurrentState): override staticstates staticcompute to let + facets survive a compute. + +2011-12-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java, + src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java: Renamed + JobExecutor to WSPLGENCallable (because it is a Callable now). In addition + to the call() method which starts the WSPLGEN process, this Callable + offers a cancelWSPLGEN() method to destroy a running WSPLGEN process. + + * src/main/java/de/intevation/flys/wsplgen/WSPLGENFuture.java: A FutureTask + that overrides cancel(boolean). Before this instance call + super.cancel(boolean), it executes WSPLGENCallable.cancelWSPLGEN() to kill + a running WSPLGEN process. + + * src/main/java/de/intevation/flys/wsplgen/Scheduler.java: The Scheduler is + no longer a Runnable. It makes now use of a ScheduledThreadPoolExecutor to + schedule the incoming WSPLGENJobs. The ScheduledThreadPoolExecutor has a + fixed number of worker threads that process the jobs. The number is 1 per + default; it can be modified using a System property "wsplgen.max.threads". + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: Added + a string constant SCHEDULER. + + * src/main/java/de/intevation/flys/wsplgen/SchedulerSetup.java: A + LifetimeListener that currently implements the systemUp() method to create + an instance of Scheduler. After its creation, the Scheduler is put into + the GlobalContext using FLYSContext.SCHEDULER as key. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Fetch the Scheduler from GlobalContext. + + * doc/conf/conf.xml: Registered SchedulerSetup as LifetimeListener. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java: + (describe): Add data items to StaticFLYSArtifacts describe-doc. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StaticState.java: + (addDefaultChartOutput): Convenienve function to add a chart-output. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + Play nice with CrossSectionArtifact. Employ blackboard. + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Spawn a CrossSectionFacet, handle various data. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Do not produce CrossSectionFacets anymore, these now "belong" to + CrossSectionArtifacts. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/cache.xml: Added cross_sections cache. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java: + (getCrossSection, getCrossSectionUncached): New, access specific + CrossSection, employ caching. + +2011-12-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + New artifact to handle cross-section access. + +2011-12-09 Raimund Renkert <raimund.renkert@intevation.de> + + Issue 413. + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Apply point size from theme attribute linewidth. + +2011-12-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java, + src/main/java/de/intevation/flys/exports/OutGenerator.java, + src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Cosmetics. + +2011-12-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java: + Documentation added, let a value be its own neighbour (distance 0). + +2011-12-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Added "Bezugslinie" to list of calculation alternatives. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: Added I18N. + +2011-12-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Further flys/issue420 fix (No Discharge Curves for Mosel). + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (includeYRange, mergeRanges): Moved NaN-guard to lowest level. + (combineXRanges): Also NaN guard the X Axis extent. + +2011-12-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial fix for flys/issue420 (Berechnete Abflusskurve: Kein Diagramm für + Mosel). Protect axis extent calculation from empty or invalid + datasets. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (includeRange, includeYRange): Renamed, updated callers. + (includeYRange): Protect from merging extent with NaNs. + (debugDatasets): Be more verbose on the datasets. + (zoom): Doc. + +2011-12-06 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue423 (Diagramm: Hauptwerte bei Abflusskurve am Pegel + werden an Y-Achse nicht angezeigt) - show not "raw" (vs interpolated) + values at Gauge. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java: + Add parameterization to let facet know whether to fetch data at + Gauges or at Artifacts position. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Let the MainValueFacets know whether to ask for interpolated + MainValues; (do not interpolate for Gauges Main Values). + (getMainValuesQ, getMainValuesW): Added parameter to control + interpolation. + +2011-12-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Modified + prefix constants for Mapserver layers and renamed constants (which have + been postfixes before). + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Adjusted + usage of Mapserver constants to the changes described above. + +2011-12-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Bugfix: Evaluate the correct parameter whether to set the floodplain or + not. In addition, the scenario parameter used by WSPLGEN is now set + correctly. + +>>>>>>> .r3356 +2011-12-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow longitudinal_section.q facets in wdiff states output. + + * doc/conf/artifacts/winfo.xml: Added longitudinal_section.q facets + to w-diff states out compatibility- matrix. + +2011-12-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactored Longitudinal*/WDiff-*Generator hierarchy and change axis + ordering, resolved label-i18n TODO. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Merge, avoid duplicate code, fix axis ordering in w-diff diagram, + label in ls-diagramm. + +2011-12-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added missing state titles. + +2011-12-05 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Do not include zero on first axis. + +2011-12-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + (buildArtifactNode): Include artifacts state data in description + document of collection. + +2011-11-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ReportGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/OutGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed superfluous imports. + +2011-11-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed import to make it compileable again. + +2011-11-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Introduce pre-rendering inter-facet communication phase ('blackboard + pass'). + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java + (doBlackboardPass): New. Before actually calling doOut, bundle + ArtifactAndFacets and let them register + themselfes as DataProvider in CallContext if they + want ("announce on blackboard"). + +2011-11-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java + (doOut): Adjusted signature. + +2011-11-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Changed doOut signature to use ArtifactAndFacet, which will be + side effect of upcoming "blackboard" feature. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java + (getRangesForDataset, getRangesForAxis): Renamed, removed TODO. + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java + (createAxis): Update call to XYChartGenerator.getRangesForAxis, + cosmetics. + + * src/main/java/de/intevation/flys/exports/OutGenerator.java + (doOut): Changed Signature to accet ArifactAndFacet instead of + Artifact and Facet. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ReportGenerator.java, + src/main/java/de/intevation/flys/exports/MapGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java + (doOut): Adjusted to new signature. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + (adjustAxes): Removed, we do not need a (manual) second axis. + +2011-11-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Fix compilation, use features of XYChartGenerator. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Set default behaviour such that 0 is not included in ranges. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Set behaviour of axis such that 0 is not (automagically) included. + +2011-11-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + Fix wrong documentation. + +2011-11-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix LongitudinalSections multi-axes plotting behavior. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Removed obsolete functions, use better working multi-axis + magic by XYChartGenerator. + +2011-11-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Overhaul dataset/axis/renderer housekeeping in Mother of all + ChartGenerators. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Refactored, keep axis/rendering relevant information in objects + of new class AxisDataset. Removed some obsolete code while adding + documentation. + +2011-11-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(relateWs): + Added the implementation of the 'Bezugslinienverfahren'. Should + be complete but needs testing! + TODO: Setup a Calculation and integrate it into WINFO. + +2011-11-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Refactored the code for the "berechnete Abflusskurve" to enable + the "Bezugslinienverfahren" to use the same code paths. It also + removes a good deal of already existing code duplication. + +2011-11-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(findQsForW): + Added method findQsForW(w, km) to retrieve the Qs that correspond + for the given w and km. + + This is to be called when doing a "W auf freier Strecke" calculation + to find out the Qs belonging to the user given W. + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Removed superfluous imports. + +2011-11-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix bug when adding Q data in LongitudinalSectionGenerator. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Add data from Q -Facet as Q over Km points. + +2011-11-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added handling of empty plots. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (createAxes, removeEmptyRangeAxes): Survive empty datasets map, create + primary axis. + (recoverEmptyPlot): New. + +2011-11-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let first visible axis be always on the left. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (createAxes): When creating axes, keep track of which is the first + one. Set its location to "left". + +2011-11-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use multiple axis in relevant generators. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + (createYAxis): Implemented. + Define and use YAXIS enum for axes. + +2011-11-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix theming and legend items for plot with multiaxis feature. + Decouple renderer index from dataset index. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + (applyThemes): Do not get renderer based on dataset/axis-index but + count. + +2011-11-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + In XYChartGenerators allow more than two datasets. + Assign axis to indices of datasets, do not show axis if corresponding + dataset is set to be not visible. + Do proper axis-setting in LongitudinalSectionGenerator only (other + will follow). Based on a patch by Sascha Teichmann. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Keep relation between index and dataset, once its added. Compute + ranges per index. Allow subclasses to override createAxes to specify + internationalized labels etc. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + Add datasets to first index. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Implement createYAxis to create correct first, second and third + axis. Added enum to easy identification of axis. Stripped down + adjustAxis which was used to create second axis. + Add datasets at correct indices. + +2011-11-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/FunctionResolver.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Cosmetics, docs. + +2011-11-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Cosmetics, docs. + +2011-11-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableCacheKey.java: + Cosmetics, docs. + +2011-11-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Resolved TODO about caching certain WstValueTables. + +2011-11-22 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java: New. + This Artifact is used to allow users adding external WMS layers to their + floodmaps. An ExternalWMSArtifact stores an URL of a WMS, the name and the + title of the WMS layer. The internal State extends WMSBackgroundState. + + * doc/conf/conf.xml: Registered the ExternalWMSArtifact. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added a + new type "floodmap.externalwms" which is used by the ExternalWMSArtifact. + + * doc/conf/artifacts/winfo.xml: Allowed the "floodmap.externalwms" facet for + floodmaps. + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java: + Some refactoring to allow easier subclassing. + +2011-11-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fixed flys/411. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + Use different queries to avoid costy joins. + +2011-11-22 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + Use different queries to avoid costy joins. Patch by Sascha + Teichmann, minor typo-fix. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added other.wkms.interpol facet + to compatibility matrix for computed discharge curves. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Resolve cosmetic todo, use importData-convenience method. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Handle STATIC_WKMS_INTERPOL and WQ/Points as Annotations. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Give Facet different name when its a flood*, so that it can be + understood to be e.g. a flood-protection further down the processing + line. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Prevent ArrayIndexOutOfBounds, log method entry. + +2011-11-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new Facet Type: Interpolated W/Km values. + +2011-11-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java, + src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java, + src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Avoid + WMS layer names that begin with digits. This would lead to invalid + WMSGetFeatureInfo responses, where the name of a layer is the name of a + XML node. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Added and use *_wq macros for interpolated + w/q data (currently used in computed discharge curve only). + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Handle STATIC_WQ_ANNOTATION type facets, build and add annotations + for these. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Set Facet type (name) based on static datas name (special case + everything starting with "height"). + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Extended compatibility matrices. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new STATIC_WQ_ANNOTATIONS Facet Type. + +2011-11-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Added a method isQueryable() that determines if a layer is queryable via + WMS GetFeatureInfo request. This method returns false as default. + + * src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java: + Override isQueryable(). All WMSDBLayerFacets are queryable via WMS + GetFeatureInfo request. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Added functionality to artifact to use single column wst + interpolators. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Added methods to create WstValueTables (interpolators) for specific + columns of wsts. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Added Point Style for other.wq data. + +2011-11-16 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Do not re-evaluate constant size() in for-loops. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Get ld_locations not locations data item to determine km. + (getDataAsDouble): New helper function to get data item as double. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Recommend fixations for computed discharge + curve outs, minor refactoring of dc conf. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Added wqinterpol factory to produce + WQKmsInterpolArtifacts. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Use StyledSeriesBuilder to add WQ data from WQKms to Series. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Handle interpolated WQ data. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java: + Adjusted to similar implementations. Added TODO about merging with + these similar implementations. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Removed logging noise, find better suited rows for interpolation. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Cache WstValueTables that were fetched by wst_id. + +2011-11-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + (getWstName): Fix and use SQL statement. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQFacet.java, + src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java: + Added new Facet and Artifact to access W over Q data. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + (importData): New function to copy data from one artifact to + another. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java + (getTable): New methods to get WstValueTable for given wst_id. + Prepolate Arrays with NaNs. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + (getWKmsName): Fix definition. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + (getWKmsName): New function. Get name (description) of a WST. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new "other.wq"/STATIC_WQ Facet-Type, e.g. for fixations in + discharge curves. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Picky cosmetics. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java, + src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java: + Cosmetics, docs. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added translations for Mosel, Elbe and Saar. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added translations + for Mosel, Elbe, Saar. + +2011-11-15 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added new interpolation mechanism to WstValueTable to interpolate + given columns only. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java + (linearW): New, interpolate a given columns w's between given rows. + (interpolateWQColumnwise): New, interpolate between rows ws at a + given column and km. + +2011-11-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Minor doc added. + +2011-11-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java, + src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java, + src/main/java/de/intevation/flys/themes/ThemeFactory.java: + Removed dead ';' from empty bodies. + +2011-11-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + s/reset/resetQuick/s in TDoubleArrayLists. + +2011-11-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Added system properties 'waterlevel' and 'km'. Useful to + init the UI with a given waterlevel and drawing the cross-sections + at the given km. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Spliting by NaNs definition holes _should_ work now. Needs + some more testing. + TODOs: + - Use log4j instead of println for logging. + - Subclass XYDifferenceRenderer instead of replacing it totally. + +2011-11-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Draw water, too. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + First code to split datasets by NaNs. WIP. + +2011-11-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Draw ground with StableXYDifferenceRenderer. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Removed XYDatasetToZeroMapper stuff. Not needed any longer + because we use rendereres on dataset basis now. + + * src/main/java/de/intevation/flys/jfree/XYDatasetToZeroMapper.java: + Removed.Not longer needed. + +2011-11-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Include computed discharge curves in dc + conf. + +2011-11-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Somewhat unify user-part of dc config. + +2011-11-11 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Modified some floodmap styles and added a + backgroundcolor attribute to polygon themes. + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + Added support for backgroundcolor. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Parse + backgroundcolor from theme document. If a value is given, the + backgroundcolor is set on the Mapserver style. + +2011-11-11 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + Set correct Mapserver attribute name to adjust the width of a line. + +2011-11-11 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added 'textcolor' and 'textsize' attributes to the + existing 'Kms' theme. + + * doc/conf/mapserver/fontset.txt: Defined a 'DefaultFont' that is used as + default font for Mapserver labels. + + * doc/conf/mapserver/db_layer.vm: Add a Mapserver LABELITEM if a value is + provided by LayerInfo object. + + * src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Added a + getLabelItem() method that returns null as default. + + * src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java: Override + getLabelItem() to return "km" which is the database field that contains + the kilometer information. + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java, + src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java: + Added an attribute labelItem with appropriate getter/setter methods. + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + Splitted up the internal class Clazz. Now, there are two new inner + classes Style and Label that fulfill the appropriate Mapfile sections of + Mapserver. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Also Read font + attributes and add new Clazz Label for the Mapserver layer. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Set the + "labelItem" attribute on the LayerInfo object used to fill DB layer + templates. + +2011-11-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Re-use macros to include more data to + datacage in more situations. + +2011-11-11 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Removed needless imports. + +2011-11-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java: New + WMSDBArtifact that creates facets for "fixpoints" relation. + + * doc/conf/artifacts/winfo.xml: Registered "floodmap.fixpoints" as valid + "floodmap" facet. + + * doc/conf/conf.xml: Registered the new WMSFixpointsArtifact. + + * doc/conf/themes.xml: Added a theme for "floodmap.fixpoints". + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + Facet type "floodmap.fixpoints". + + * doc/conf/meta-data.xml: Made "floodmap.fixpoints" available via datacage. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added titles for + "floodmap.fixpoints" facets. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Refactored and (re)use macros. + +2011-11-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java: New + WMSDBArtifact that creates facets for "buildings" relation. + + * doc/conf/artifacts/winfo.xml: Registered "floodmap.buildings" as valid + "floodmap" facet. + + * doc/conf/conf.xml: Registered the new WMSBuildingsArtifact. + + * doc/conf/themes.xml: Added a theme for "floodmap.buildings". + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + Facet type "floodmap.buildings". + + * doc/conf/meta-data.xml: Made "floodmap.buildings" available via datacage. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added titles for + "floodmap.buildings" facets. + +2011-11-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java: New + WMSDBArtifact that creates facets for "lines" relation. + + * doc/conf/artifacts/winfo.xml: Registered "floodmap.lines" as valid + "floodmap" facet. + + * doc/conf/conf.xml: Registered the new WMSLineArtifact. + + * doc/conf/themes.xml: Added a theme for "floodmap.lines". + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + Facet type "floodmap.lines". + + * doc/conf/meta-data.xml: Made "floodmap.lines" available via datacage. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added titles for facets. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Adjusted DC configuration to + also allow heightmarks and base data in discharge longitudinal + sections. Minor refac. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Adjusted DC configuration to let old + calculations be available for discharge longitudinal sections. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + Handle other WQKm and WKm Facets. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java + (IS): New inner class with static method to allow queries whether + a type belongs to a however-defined "group". + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Reverted accidental commit. + + * doc/conf/meta-data.xml: Extracted annotations-macro, add recommendation + for discharge longitudinal sections. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: Reverted accidental commit. + + * doc/conf/meta-data.xml: Extracted annotations-macro, add recommendation + for discharge longitudinal sections. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Made discharge longitudinal section out compatible with annotations. + + * doc/conf/artifacts/winfo.xml: Added facets to compatibility list + for discharge longitudinal section outs. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Extracted Annotations-Macro in dc conf, recommend Annotations for + discharge longitudinal sections. (Note correction two commits later). + + * doc/conf/conf.xml: Extracted annotations-macro, add recommendation + for discharge longitudinal sections. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Handle Annotations in DischargeLongitudinalSection diagrams. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + Call doAnnotations for LONGITUDINAL_ANNOTATION facets. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Resolve code duplicate. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java + (doAnnotationsOut): Removed duplicate code. + Theoretically handle WQKMS data. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Adjusted call to doAnnotationOut. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java + (doAnnotations): Doc from LongitudinalSectionGenerator. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Include exception when logging issue with spline creation. + +2011-11-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + When during XPath evaluation an exception is thrown, log the + expression that caused the trouble. + +2011-11-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Use separate XYDataset for each curve. This is needed because + "Raum/Flaeche" needs specialized renderers, which are not compatible + with the standard renderers. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + Removed superfluous import. + +2011-11-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java: New + Artifact that is used to create WMS layers for floodplains in maps. + + * doc/conf/conf.xml: Registered the new WMSFloodplainArtifact. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + a new type 'floodmap.floodplain'. + + * doc/conf/artifacts/winfo.xml: Registered the 'floodmap.floodplain' facet + for floodmaps. + + * doc/conf/themes.xml: Added a theme for 'floodmap.floodplain' facets. + + * doc/conf/meta-data.xml: Added configuration for 'floodplain'. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added facet titles for + 'floodmap.floodplain' facets. + +2011-11-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java: New + Artifact that is used to create WMS layers for catchments in maps. + + * doc/conf/conf.xml: Registered the new WMSCatchmentArtifact. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + a new type 'floodmap.catchment'. + + * doc/conf/artifacts/winfo.xml: Registered the 'floodmap.catchment' facet + for floodmaps. + + * doc/conf/themes.xml: Added a theme for 'floodmap.catchment' facets. + + * doc/conf/meta-data.xml: Added configuration for 'catchments'. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added facet titles for + 'floodmap.catchment' facets. + +2011-11-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java: New + Artifact that is used to create WMS layers for flood protected works. + + * doc/conf/conf.xml: Registered the new WMSHwsArtifact. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + a new type 'floodmap.hws'. + + * doc/conf/artifacts/winfo.xml: Registered the 'floodmap.hws' facet for + floodmaps. + + * doc/conf/themes.xml: Added a theme for 'floodmap.hws' facets. + + * doc/conf/meta-data.xml: Added configuration for 'hws'. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added facet titles for + 'floodmap.hws' facets. + +2011-11-09 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/dbconnection.include: Removed. DB connections are + supported by LayerInfo objects now. So, we do not need to configure it any + more. + + * doc/conf/mapserver/db_layer.vm: The database connection is provided by + LayerInfo objects. The "INCLUDE dbconnection.include" has been replaced. + + * src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: The inner + State class got two new methods that provide information about db + connection string and connection type. + + * src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Both + classes support getter/setter for connection and connectionType. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Fill + LayerInfo objects used to create DB layers with the connection and + connection type provided by WMSDBLayerFacet. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Allow height marks with points style in w-differences diagrams. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Handle HEIGHTMARKS_POINTS facets. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Made Q Duration curve initially inactive. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (getInitialFacetActivity): Return 0 for DURATION_Q facets. Minor + cosmetics. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Recommend mainvalues for Duration Curve Diagrams. + + * doc/conf/meta-data.xml: Recommend mainvalues for duration curve + diagrams. refactored into macro. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Handle MainValue Facets in Duration Curve Diagrams. + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Handle MainValues. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Adjusted to call doAnnotations. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Move do*Annotation* (like mainvalue) in XYChartGenerator. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java + (doAnnotations): New, moved from DischargeCurveGenerator. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java + (doMainValueAnnotations): Moved to superclass. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Removed duplicate code. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java + (): Minor cosmetics, added stability. + (getInitialFacetActivity): Let facets be inactive in duration curve + diagrams. + +2011-11-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Allow other.wqkms facets in many + outputs, mainvalues in duration curves. + +2011-11-09 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/dbconnection.include: Adapted connection params for + using an oracle database. + + * src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: + Added Oracle support for Mapserver's DATA attribute. Oracle doesn't allow + a "USING UNIQUE id" string in this attribute which is required by Postgis. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Modified the geometry type of "talaue.shp" from MultiPolygon to Polygon. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function + which returns true, if the backend uses an Oracle db instance. Otherwise, + it returns false. + +2011-11-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue406 (Themestyle-editor: themes for "other.wkms" and + "other.wqkms" missing) + + * doc/conf/themes.xml: Fixed typos in WKms and WQKms theme names. + +2011-11-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue405 (Datacage: Recommendations get loaded twice). + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java + (setup): Do not try/catch exception. + (spawn_state): Generate just one "general" output. + +2011-11-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Added a log.warn() which prints out an exception - previously it was + just skipped. + +2011-11-08 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Removed orphaned datacage configuration which is + no longer loadable. + +2011-11-07 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added an "post-describe" hook which is necessary to + load recommendations for "floodmaps". + +2011-11-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java + (loadRows, loadColumns, loadQRanges): Refactored in preparation to + ability to create WstValueTables for given wst_id and + column_pos (interpolation for static data). + +2011-11-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + Minor, picky cosmetics. + + * src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java: + Removed junk. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Added documentation. + +2011-11-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Be more specific in what to catch. + +2011-11-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Added the CrossSectionTracks to the "floodmap" + datacage configuration. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added a + FacetType "floodmap.qps". + + * doc/conf/conf.xml: Defined an ArtifactFactory for the "wmspqsartifact" + string. The factory will create new instances of WMSQPSArtifact. + + * src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java: New. This + Artifact is used to create "floodmap.qps" facets. It has an internal fixed + State WMSQPSState. + + * doc/conf/artifacts/winfo.xml: Added the "floodmap.qps" layer to the + "floodmap" output. + + * doc/conf/themes.xml: Added a theme for "floodmap.qps" facets. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings for the QPS WMS + layer used in floodmaps. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Re-enable mainvalue-recommendations for computed discharge curves, + as the NPE should be gone. + + * doc/conf/meta-data.xml: Uncomment mainvalue recommendations. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + When querying metadata/datacage, use only output-names of outputs that + actually exists (in the sense of having facets). + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + Get output names from artifact, not from state. + +2011-11-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Removed DEMs from floodmap configuration, + because we are not able to draw DEMs into maps. + +2011-11-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: + Subclasses WMSDBArtifact now and defines an inner class RiverAxisState + which subclasses WMSDBState. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Removed. The RiverAxisState is an inner class of RiverAxisArtifact now + which subclasses WMSDBState. + + * doc/conf/artifacts/riveraxis.xml: Removed, because the RiverAxisArtifact + has a fixed static State only. + + * doc/conf/conf.xml: Removed riveraxis.xml definition. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + For a Flys-Collection, add outputt to attributes-part of describe + document only if they contain facets. -> Prevent empty output nodes + in flys-collections outputs. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + (writeFacets): Added return type to indicate whether any facet was + written. Decide whether to add an output-node depending on this + return value. + +2011-11-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Create + line and polygon layers for barriers only if they are really existing. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Disable mainvalue-recommendations for discharge curves as they trigger + a yet-to-be understood NPE. + + * doc/conf/meta-data.xml: Comment mainvalue-recommendations for + discharge curves. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added new matching condition for theme-mappings: the name of + the output. + + * src/main/java/de/intevation/flys/themes/ThemeMapping.java: + Added output field and function to match it against a given + output name. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Createing ThemeMapping with output attribute from configuration. + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: + (getTheme(FLYSContext, string)): Removed, never called. + (getTheme): Added outputName argument, match it. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Pass outputs name until it can be matched against mapping. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Added default themes for other.w(q)kms. + +2011-11-04 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Cosmetics, reduce logging noise. + +2011-11-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added access to static W_Q_Kms - data in much the same way then static + WKms. + + * src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java: + Cache Key for static wqkms data. + + * src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java: + Facet for WQKms. + + * src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java: + Factory to access WQKms. + + * src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java: + Artifact that provides 'static' WQKms. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added STATIC_WQKMS type. + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/XYDatasetToZeroMapper.java: + New. Maps series to zero to be compatible with XYDifferenceRenderer. + It returns an iterator over XYDatasets to enable splitting by NaNs, + which still needs to be implemented. + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + Uses a XYDatasetToZeroMapper now. Fixed package name. + +2011-11-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added new matching options for theme-mappings to allow more + overspecification of defaults (e.g. now name,description-pattern and + master-artifacts attributes are matched). The first full match from + the configuration file is done. + New matching option in the masterAttr- field of a mapping are + super-basic until new use-cases come up. + Concrete new themes are point-styles of Ws when locations where chosen + to calculate. + + * doc/conf/themes.xml: Added newly defined Themes. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Put master-artifact in flys-context. + + * src/main/java/de/intevation/flys/themes/ThemeMapping.java: + Accept masterAttr in constructor. + (masterAttrMatches): New, check masterAttr-condition against + artifact. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + When creating ThemeMappings, pass in masterAttr. + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: + (getTheme): Evaluate masterAttr-condition, always return first full + match. + +2011-11-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: + Added ARTIFACT key, documentation. + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java: + New. At the moment a pure copy of JFreeChart's XYDifferenceRenderer. + Needs to be refactored to cope with its limitations: + + - Series numbers need to be zero based. We have more than two series + in our diagrams. + + - Cannot handle definition holes indicated by NaNs. We have these + cases e.g. more than one "Fliessbereich". + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Reenabled dumping data to disk. + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Removed superfluous import. + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Use new pair in stack of results and connections because they are + always used in pairs. Maintaining two separate stacks is not + needed any longer. + +2011-11-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/Pair.java: New. A generic pair. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Rewritten to useful as test bed for "Raum/Flaeche" operations. + +2011-11-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Added + setter methods for all parameters and removed the constructors. There is + just an empty constructor - all parameters need to be set via setter + methods. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Modified the + creation of LayerInfo objects. + + * src/main/java/de/intevation/flys/artifacts/model/DBLayerInfo.java: + Removed, because the internal structure and constructors of LayerInfo have + changed, so that we gonna use LayerInfo for all layers now. + + * doc/conf/themes.xml: Modified the color definitions of + 'floodmap.riveraxis' and 'floodmap.kms' themes and added a 'symbol' field + to 'floodmap.kms'. + + * doc/conf/mapserver/symbols.sym, + doc/conf/mapserver/fontset.txt: New. Required by Mapserver. + + * doc/conf/mapserver/db_layer.vm: Added an 'EXTENT' field that is filled + using LayerInfo.getExtent(). + + * doc/conf/mapserver/mapfile.vm: Modified FONTSET directory and added a + SYMBOLSET. + + * src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Added an + abstract method getGeometryType(). + + * src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java: Override + getGeometryType() of WMSDBArtifact. This Artifact provides "POINT"s. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Create new WMSDBLayerFacets with geometry type "LINE". + + * src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java: + Added a 'geometryType' attribute and getter/setter methods. This attribute + determines the type of geometry provided by this database wms layer. Types + could be "POLYGON", "POINT", "LINE" and so on. + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + Added a 'symbol' attribute to the inner class Clazz. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added a function to + parse the symbol field of a theme. This symbol is used for + MapserverStyle.Clazz. + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Apply point theme to heightmarks when imported in longitudinal + section diagram. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new FacetType HEIGHTMARK_POINTS. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java: + Allow name to be given in constructor. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + If heightmarks were loaded, give respective name in WKmsFacet + generation. + + * doc/conf/themes.xml: Added virtual "Points" and concrete + heightmark_points - theme. + + * doc/conf/artifacts/winfo.xml: Made longitudinal_section output + compatible with heightmarks_points. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Render heightmarks like other wkms. + + * doc/conf/meta-data.xml: Changed heightmark ids such that it can be + identified in StaticWKmsFacet . + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Documentation added. + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java: + Fix bug where (wrong) active-attribute was set, doc. + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactoring to allow mainvalues in both discharge and computed + discharge curve diagrams. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java + (addPointsQW): New helper function. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Moved doMainValueQAnnotations, doMainValueWAnnotations from child- + to parent-class, extracetd doDischargeOut. Use + StyledSeriesBuilder.addPointsQW . + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Removed logger/debugging noise. + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + 1) Pass outputs name to artifacts getInitialFacetActivity(). + 2) Do not allow "gaps" in positions of facets in outputs in attributes + of collection (prevent e.g. positions 1,3,5; will become 1,2,3 + instead). + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Pass outputname to artifacts getInitialFacetActivity(), prevent + gaps in facets positions in outputs (1,3,10 become 1,2,3). + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + 1) Give Artifacts information about the out when they have to decide + whether a given facet is initially in/active by adding parameter + to getInitialFacetActivity(+outputName). + 2) Generate separate Set of MainValueFacets for discharge curves. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + (getInitialFacetActivity): Adjusted, new parameter outputName. + Added MAINVALUES_{Q,W} definition. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java: + Accept name in constructor. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Create second pair of MainValuesFacets, give distinguishable names. + +2011-11-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added compatibility of (computed)discharge-curve diagrams with + mainvalues. + + * doc/conf/artifacts/winfo.xml: Added mainvalues to compatibility list + of (computed) discharge curve outputs. These facet-definitionss can + differ in names because we can can have up to 4 mainvalue facets in + one state. + +2011-11-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java: Determine + the extent of such WMS layer based on the list of RiverAxisKm objects + returned by the backend. + +2011-11-01 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Added a datacage node that represents a + kilometer WMS layer. + + * doc/conf/conf.xml: Added a new Artifact WMSKmArtifact. + + * doc/conf/themes.xml: Added a style for 'floodmap.kms' facets. + + * doc/conf/artifacts/winfo.xml: Defined 'floodmap.kms' as valid floodmap + facet. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + a 'floodmap.kms' facet. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a method to + determine the srid of a river based on its name. + + * src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: New. This + Artifact should act as base Artifact for WMS layers that represent data + from database datastore. + + * src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java: New. This + Artifact is used to generate facets for kilometer WMS layers. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added default descriptions + for 'floodmap.kms' facets. + +2011-11-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix incompilability. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java: + Adjust to changed CrossSectionFacet. + +2011-11-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Minor preparations to handle multiple cross sections in one + diagram/artifact, faking certain aspects (e.g. ability to display + multiple cross sections, but let these fetch the exactly same data + for now). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Parameterize but fake access to cross-section (always take first + one). + (getCrossSectionName,getCrossSectionNames): Renamed, access names + of all cross-sections, so that at least facets with different names + are created (they will still deliver the same data). + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + Allow indexing. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Index created cross-sections. + +2011-11-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Show multiple water lines and facets in cross-section diagram if + multiple waterlevel values had been entered. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java + (appendBackgroundActivity): Made static. + (getWaterLines): Add 'idx' argument to specify index of queried + waterlevel. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Add index. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Add one Facet for each of the computed waterlevels. + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java: + Added code to calculate intersection points. + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + Added polygons for trivial cases. WIP + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + Made it compilable again. + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java: + Made X() and Y() access macros public. + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + More code. WIP. + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + Handle start points when building polygons. Work in progress. + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java: + New. Vector operations on Point2D. + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + Moved vector operations to VectorUtils. + +2011-10-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + Do not call size() in for loop again and again. + +2011-10-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: + Interim check in. Work in progress. + +2011-10-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java: New. + Polygon class to help creating "Raum/Flaeche" renderers with gaps in + their definitions. WORK IN PROGRESS! + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added a default theme for the riveraxis used in the + floodmap. + + * src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java: + New. This class is used by ThemeUtil to create a style which is + compatible for Mapserver- + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added a method to + retrieve a Mapserver compatible style (as string) based on a given + Document (that comes from CollectionItem's attribute). + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: + Implemented the setStyle() and getStyle() methods. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Added a + new parameter 'style' to createDatabaseLayer(). This parameter is set on + LayerInfo. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Create + Mapserver compatible styles and call createDatabaseLayer() with this + style. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Defined "floodmap.riveraxis" and + "floodmap.wmsbackground" as compatible layers for the floodmap output. + + * doc/conf/mapserver/db_layer.vm: New. This layer template is used for + Mapserver layers with database datastore. + + * doc/conf/mapserver/dbconnection.include: New. The database configuration + used in the db_layer template. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a method + getUserWMSUrl() that returns the URL to the user specific WMS server. + This method requires a UUID of an Artifact to identify the owner of the + Artifact. + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Use + FLYSUtils.getUserWMSUrl() to create the URL to the user WMS for + WMSLayerFacets creation. + + * src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java: + New. Subclasses WMSLayerFacet to save data and filter parameters used + for database storage in Mapfiles. + + * src/main/java/de/intevation/flys/artifacts/model/DBLayerInfo.java: New. + Subclasses LayerInfo to save database relevant parameters. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Creates new WMSDBLayerFacets, so that the riveraxis layer data is + fetched from database. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Added a + public method that allows creating layers (type LINE) based on + WMSDBLayerFacets. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Enabled + support for Facets other than "floodmap.wsplgen" and "floodmap.barriers". + Those other Facets are supposed to be WMSDBLayerFacets. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactored, added StyledSeriesBuilder to unify adding points to + XYSeries. + + * src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java: + New class to help with adding points to XYSeries. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Use StyledSeriesBuilder to add points to series. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added DC-conf, such that static data can be loaded from w-difference + diagrams datacage. + + * doc/conf/meta-data.xml: Minor "refactoring" (definition of two + macros, allow certain static data to be loaded via datacage to + w-difference diagrams, too. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Load and display annotations in w-differences, minor polishing. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Use FacetType 'instead' of string. Allow Annotations in + WDifferences- diagram. + + * doc/conf/meta-data.xml: Recommend annotations in w-differences case. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Survive case where a given output doesnt exist in compatibility + matrix. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StaticState.java: + Added simpler constructor. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Adjusted construction of StaticStates. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Allow Annotations in longitudinal and + w-differences diagrams. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use artifacts configuration (e.g. winfo.xml) to define which facets + can be used in which output. Hide no-matches. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added use of "compatibility matrix". Only include facets in in + collections description document that are marked compatible in the + masterartifacts configuration (e.g. winfo.xml). + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java + (mergeAttributes, getMasterArtifact): Extraced, updated caller. + Cosmetics to reduce indentation one step. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java + (getStateHistoryIds): New, return list of current and all previous + state ids. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Trigger the re-creation of FLYS mapfile if endOfLife() of this state is + called. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/mapfile.vm: The "layers" injected by VelocityEngine is + now used to include layers. A single string in this list represents the + path to a file which contains a LAYER section for Mapserver' Mapfile. + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: Removed the + update() call of MapfileGenerator. Mapfiles are generated by MapGenerator + only which requires a FLYSArtifactCollection.doOut()! + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Call update() + of MapfileGenerator to trigger the re-creation of mapfile(s). + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Collect all + LAYER snippets from filesystem and inject the filepath for each snippet + into the Mapfile template. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Cosmetics, doc. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let OutputParser and AttributeParser collect all facets on the way. + + * src/main/java/de/intevation/flys/collections/OutputParser.java, + src/main/java/de/intevation/flys/collections/AttributeParser.java: + Collect all facets while iterating over Outputs and Attributes, + documentation added. + +2011-10-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Extracted getFlysContext from FLYSArtifacts into FLYSUtils. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java + (getFlysContext): Added, extracted from FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + (getFlysContext): Moved to FLYSUtils, updated callers. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Update callers to getFlysContext. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Bugfix: + Catch IOException - flys-artifacts compiles again. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Defined "floodmap.barriers" as valid facet + for floodmaps. + + * doc/conf/mapserver/shapefile_layer.vm: New. Currently a copy of + layer.vm. This template will evolve to a special mapserver layer + template with a shapefile data source. + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Fixed broken + facet name of barriers. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Added + public methods for creating wsplgen and barriers layer files for + mapserver. + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: Use + MapfileGenerator to create new layer files for wsplgen and barriers. + +2011-10-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Added new + method gerRiverBoundary() which returns an Envelope object (which + represents the bounding box of a Geometry) of a riveraxis specified by its + rivername. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: Use + Geometry.getRiverBoundary() to determine the max extent of a river. + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java, + src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: Use + JTS Envelope to save the bounding boxes of WMS layers. + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java: + Adapted the code to apply the changes in GeometryUtils (use Envelope to + determine the max extent of the river axis). + + * src/main/java/de/intevation/flys/exports/MapGenerator.java: New (work in + progress). This Generator will currently return a map configuration in XML + which consists of parameters required by OpenLayers to create a map. + + * doc/conf/conf.xml: Registered the new MapGenerator. + +2011-10-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Do not recommend historical data to load + when having computational discharge curves. + +2011-10-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Reduce noise, given "error" message was more of "debug" nature. + +2011-10-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Restore mapping of state id to facets (essentially revert, revision + 3083 and 3088). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + (getInitialFacetActivity): Be more explicit on which facets to + introduce inactivated. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Minor refactoring, declare a string final static. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Restore association from state id to facets. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/collections/OutputParser.java: + Cosmetics, documentation. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Prepare rendering of "other/static wkms" (functional) and + w-differences (not yet fully functional). + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Cosmetics. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: + Do not store facets in a map from stateId to list of facets, but in + a pure list instead. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/artifacts/winfo.xml: Adjusted to newer semantics, + minor cleanups. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Resolve association of facets to states in artifacts. This eases + merging of outputs and facets and inhibition of unwanted outputs + substiantially (at the price of slightly more expensive merging). + Also, the semantics of artifacts configuration files (e.g. winfo.xml) + is changed (facet elements within an output elements are used for + merging). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Do not store facets in a map from stateId to list of facets, but in + a pure list instead. + +2011-10-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Added dc configuration for some data + that can be loaded from longitudinal section diagrams. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Cosmetics, docs. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let Qs in Longitudinal Diagram be inactive, initally. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + (getInitialFacetActivity): Do not let Facets ending with a 'q' + enter in active state. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Fix broken datacage config. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Configured to include correct id to + clone artifact that produces w-diff. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Revert correct behaviour of Annotations (the small axis tick shall + always be drawn). Minor refactoring. + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Added configuration to include differences + in datacage when longitudinal sections are shown (yet not + functional). + +2011-10-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: Cosmetics. + +2011-10-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/themes.xml: Added theme for w_differences facets. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java + (createSecondAxisRange): Survive parameter-nullness for now. + Added documentation. + +2011-10-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/themes/ThemeAccess.java: + New. Caching wrapper around an XML document theme. It uses ThemeUtil + to access the values and stores them in instance variable. + Background: ThemeUtil use XPath a lot which is expensive. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Use ThemeAccess to style the annotations. + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Removed some XPath strings. They are in ThemeUtil. + +2011-10-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Added methods to parse further attributes. + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Apply the theme attributes and use ThemeUtils to get the attribute values. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Removed the spamy debug output. + +2011-10-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + To obtain the size of a diagram it is rendered twice. The + second time the generated image is omitted so the concrete + rendered image is not needed. To save CPU cycles in this pass + the image is rendered to to /dev/null Graphics2D object. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Added boolean system property "info.rendering.nop.graphics" (default: false). + With this property set the info rendering is done via a new + NOPGraphics2D opbject which does not render the image. + + * src/main/java/de/intevation/flys/java2d/NOPGraphics2D.java: + New. Implements java.awt.Graphics2D trivial empty methods. + This prevents rendering. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Commented out spamy debug output + +2011-10-21 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Draw the text background and use orientation attribute. + +2011-10-21 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Renamed 'textbackground' to 'backgroundcolor' to have 'color' in the + attribute name. + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Process text attributes correctly. + +2011-10-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java: + New. Service to lookup the Nth nearest neighbors for a set of given + cross section ids and kms. + + * doc/conf/conf.xml: Registered service. + + * doc/conf/cache.xml: Cache config. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Removed superfluous imports. + +2011-10-20 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Added methods to extract further attributes from theme. + +2011-10-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added main value themes for longitudinal section + charts. + + * src/main/java/de/intevation/flys/themes/ThemeMapping.java: New. This + class stores the name of a facet, the related theme and a pattern + string. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Read the pattern string and store a list of ThemeMapping objects in the + FLYSContext. + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: Modified + getTheme() which now takes the FLYSContext, the name of a facet and an + optional pattern string. Now, we can have specialized Themes for each + chart type. E.g. the facet "longitudinal_section.w" maps the default + Theme for W lines in longitudinal section charts. If the optional + pattern string matches the pattern ".*(HQ1000)(\D.*)*", the ThemeFactory + will return the Theme "LongitudinalSectionW_HQ1000". + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Use the description of a facet as pattern string to get the relevant + Theme from ThemeFactory. + +2011-10-20 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added new theme attributes. + +2011-10-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix WDifference plots where masterartifact has no range set. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + (addSubtitles): Overridden, the master artifact has no + range. + +2011-10-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix masterartifact in collections in cases where the original + masterartifacts facets do not come first in certain list. Query + 'backend'/db instead. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Set 'real' master artifact, defined to be oldest belonging to this + collection. + +2011-10-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java, + src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Modified the method signature of createStaticData() which now also + requires a FLYSArtifact. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Override createStaticData() to create titles for Qs manually - we want + to display the named main values if existing for the selected Qs. + +2011-10-19 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + ComputedDischargeCurveW and ComputedDischargeCurveQ inherit attributes from + theme 'Text'. + +2011-10-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue316 + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: Added + constructor to not sort the data. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Use the not sorting constructor of StyledXYSeries. + +2011-10-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + moved the code to create WSP W and Q facet names to FLYSUtils. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: New functions for + creating WSP W and Q facet names and for querying a named main value + based on a given gauge and value. The names of W and Q facets will now + depend on the selected Q and Q mode: if the mode is "q at gauge" and a + named value is found for the given value, the facet's name contains the + named value instead of the value itself. + +2011-10-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix datacage configuration to let client load ZUS and flood + protections. + + * doc/conf/meta-data.xml: Use 'ids' instead of 'id' to help client. + +2011-10-19 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + Added methods to parse text attributes from theme document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Apply a theme to axis annotations. + +2011-10-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Create (data) Label from data string (client will be adjusted to send + the name). + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Create label from input data string, documentation added, junk + removed. + +2011-10-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java(zoom): + Do not crash if no axis is given. + +2011-10-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Added + getFormat() which extracts the format string from XML request document. + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: Adapted + method signatures of exportImage(), exportSVG() and exportPDF(). All + methods now take a CallContext object which stores extra chart export + parameters. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Enabled PDF and SVG chart exports based on the "format" string given in + the XML request document. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Simplify rendereing W(Q)Kms in WDifferencesCurveGenerator. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + (doWOut, doWOut): Simplified. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Render zus and flood-protections in WDifferences-diagrams. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Added basic respect of "other.wkms"- facets. + + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Adjusted Datacage-Configuration to fetch "extra longitudinal...." + (.zus) - waterlevels in certain case (in system-part). + + * doc/conf/meta-data.xml: Adjusted to present extra-kms with + staticwkms factory in certain case. + +2011-10-17 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/themes.xml: + Added new virtual theme for text with the attributes 'font', 'textcolor' + and 'textsize'. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Give StaticWKmsArtifacts proper names, and pre-deselect them. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + (getInitialFacetActivity): Overridden to let facets enter plot + inactively. + (setup): Give Facets the name of the Wst. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + Refactored to expose getWKmsName separately. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Adjusted Datacage-Configuration to fetch flood-protections when + waterlevels are requested (in system-part). + + * doc/conf/meta-data.xml: Adjusted to present flood-protections with + staticwkms factory in certain case. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Register staticwkms factory. + + * doc/conf/conf.xml: Register staticwkms factory to spawn StaticWKms- + Artifacts. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fetch name of static WKms. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + Removed dependence on "kind", but fetch name for created WKms. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Remove dependence on Kind. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Store parameterization in data, not in Artifact. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Resolve col_pos and wst_id field, use data instead. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add convenience-method to add defaultdata (string). + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + (addStringData): Add Default (String) Data . + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add a new Artifact and Facet (StaticWKmsArtifact, WKmsFacet) to + access WKms obtainable with the WKmsFactory. + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + New, artifact with single state to get WKms from WKmsFactory. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java: + New Facet to display W over km. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new type name. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add WKMsFactory to access 'static' wst-data. + + * src/main/java/de/intevation/flys/artifacts/model/StaticWKmsCacheKey.java: + Cache Key for the static WKms data. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java: + New, creates WKms from wst-id and column. Does not yet fetch the + name. + + * doc/conf/cache.xml: Added cache configuration for static wkms data. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, docs. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: + Cosmetics, docs. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java: + Added constructor that takes name, docs. + +2011-10-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix issue that Annotations do not come with theme/style. + + * doc/conf/themes.xml: Added "Annotations" default style. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Set style of annotations, minor cosmetics. + +2011-10-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Made inner class ThemeList static. + s/new Integer(small)/Integer.valueOf(small)/ + +2011-10-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + The inner class ThemeList makes now use of ManagedDomFacet to read the + attributes of Facets saved in the Collection's attribute. + +2011-10-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue314: Variables in datacage are now case insensitive. + (H2 returns meta data variables uppercase) + + * doc/conf/meta-data.xml: + Made a statement more precise. Added some debug output. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java: + Use uppercase variable names. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/FunctionResolver.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/ResultData.java: + Variables are now treated as uppercase. + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + Input variables are now treated uppercase. + +2011-10-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java: + Prepared Facets to support a "visible" attribute. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: Adapted + the constructor call of ManagedFacetAdapter. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + The inner class ThemeList now supports the "visible" attribute of + ManagedFacets. + +2011-10-17 Raimund Renkert <raimund.renkert@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: + Added method to apply line type. + + * doc/conf/themes.xml: + Changed initial default value for line type. + +2011-10-17 Ingo Weinzierl <ingo@intevation.de> + + flys/issue226 (W-INFO: Dauerlinienberechung /Abbbildung x-Achse) + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Set the upper bound of these charts to 364. + +2011-10-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugesFactory.java: + Added a function that returns a Gauge based on its name. + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java: + Create proper descriptions for facets. + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: Added a + setter for labels. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Use the string returned by Facet.getDescription() as series names. The + ThemePanel and the Legend will always display the same titles for curves + now. + + +2011-10-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue363 (W-INFO/ Abflusskurve, Extremwert-Rendering). + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + (parseLineWidth): New. Get line width from Document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + When adding annotations, parse line width from theme, set it. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + When painting, set Paint and stroke early enough. + +2011-10-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Put the + config directory into the Velocity context. It is available as + '$CONFIGDIR' in templates. + + * doc/conf/mapserver/mapfile.vm: Set the debug file to + "$CONFIGDIR/flys-user-wms.log" and added a LEGEND section. + + * doc/conf/mapserver/wsplgen_class.vm: Adapted the class names. Those + names are displayed in the image served by GetLegendGraphic. + +2011-10-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add possibility of programmatic configuration of initial "activity" + state (active or inactive) of (Managed)Facets by introducing + FLYSArtifact.getInitialFacetActivity. This method shall be overriden + by subclasses where Facets are wanted to come to live inactive. + Artifacts will be asked only once how the MangedFacet should come to live, + namely when AttributeWriter finds a genuinely new Facet. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java + (getInitialFacetActivity): + New function to let Artifact decide whether a ManagedFacet shall + initially be set to active or inactive. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Accept database in constructor. For genuinely new Facets, spawn its + mother artifact and ask whether the (Managed)Facet shall be active + or inactive (initially). + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java + (buildOutAttributes): Pass database to AttributeWrite (which needs it + to spawn artifacts), rename items parameter to reflect content. + +2011-10-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, removed obsolete imports. + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Removed obsolete imports. + +2011-10-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Added a further attribute "mark.selected" to the barriers feature type. + This attribute is used in the client, where we are not able to remove it + properly. Reading the GeoJSON string without this attribute is no longer + possible... strange! + +2011-10-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added i18n for label of wdiff "pair select" states data. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n for + state.winfo.waterlevel_pair_select . + +2011-10-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Addressed "Wrong labels" [6] part of flys/issue371 (W-INFO / Differenzen: + Anmerkungen zur Umsetzung) . + + * src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + Adjusted variable names to avoid conflict in subclasses, adjusted + default value for i18n string. + +2011-10-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, docs. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Cosmetics: Space after full stop in commments, slightly improved + documentation, added one debug message. + +2011-10-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix remainder of flys/issue304 (Erweiterte Funktionen W-Differenzen) . + + * doc/conf/artifacts/winfo.xml: Removed obsolete data of + WDifferencesState. + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java: + Re-enable facet-filtering, but adjust filters before that happens + (former longitudinal_section output is now w_differences output). + +2011-10-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added wdiff-chart translations. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n for wdiff. + +2011-10-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Expose translateable Strings as constants. + +2011-10-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix most labels in w-differences charts. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Remove most static final i18n-variables in favor of direct String + usage or usage of methods. By this, allow easier adoption of labels + in subclasses. + +2011-10-11 Ingo Weinzierl <ingo@intevation.de> + + flys/issue383 (Zweite Y-Achse wird beim Zoomen/Verschieben nicht angepasst.) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Call adjustAxes() before applying zoom settings with autoZoom(). We need + to add new y-axes first before we adjust their ranges. + +2011-10-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + s/new Integer(small)/Integer.valueOf(small)/ + +2011-10-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Do not fire change events for each and every data point added. + +2011-10-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix WDifferences with more than one Pair (crashed due to incorrect index for + facets.) + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Fix wrong index for difference facets (allows for more than one + difference facet per artifact without crashes). + +2011-10-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Use slightly modified doWOut-implementation from + LongitudinalSectionGenerator (here need to add Ws to different axis). + +2011-10-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Fix import/reference. + +2011-10-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let WaterlevelPairSelectState include diffids-data (if any) to enable + future work on repopulation of Grid in GUI when jumping back + (reparameterization). + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + (createItems): Override to include old data. + +2011-10-10 Ingo Weinzierl <ingo@intevation.de> + + flys/issue150 (Diagramm: Anzeige von W bergauf) + flys/issue345 (W-INFO / Wasserspiegellagenberechnung, Diagrammausgabe) + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Corrected the determination to invert the x axis, so that waterlines + will start with their highest value at the left and end with their + lowest values at the right. + +2011-10-10 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java: + Cosmetics, added an (@Override) annotation. + + * src/main/java/de/intevation/flys/artifacts/model/CalculationResult.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Cosmetics, added documentation. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Cosmetics, whitespace after full stops in comments, added + (@Override) annotation. + +2011-10-10 Ingo Weinzierl <ingo@intevation.de> + + flys/issue220 (Diagramm: Achsenbeschriftungen an verschiedenen Achsen müssen gleich aussehen) + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Adjusted the label font of the 2nd y-axis - now, both axes labels look + equal. + +2011-10-10 Ingo Weinzierl <ingo@intevation.de> + + flys/issue189 (WINFO/Dauerlinie: Sortierung der Berechnungsausgabe nach Dauerzahlen aufsteigend) + + * src/main/java/de/intevation/flys/artifacts/model/WQDay.java: Added a + method that determines if the items (days) in this object are increasing + or not. + + * src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + Changed the order of the CSV export - the highest day is at the top of + the export; the lowest day is at the bottom. + +2011-10-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Worked on flys/issue150 (Diagramm: Anzeige von W bergauf). + Still does not work in all cases. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java (generateChart()): + Reordered calls to ensure that the inversion of the x axis is + not eliminated by other chart generation steps as a side effect. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Assuming that JFreeChart is inverting axis automatically if the + KMs are reversed ordered only do invert only in some situations. + + Do not invert axis for Q (@Ingo: This is wrong! We must do this + if we are only displaying the Qs and the Ws are deactived). + +2011-10-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Take care on empty ranges while preparing ranges for single points. + +2011-10-07 Ingo Weinzierl <ingo@intevation.de> + + flys/issue114 (W-INFO: Wasserspiegellagenberechnung / Ort (Spezialfall: Generierung eines Diagramms bei punkthafter Berechnung)) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Expand + ranges for x and y axes if there is just a single point in a series - + JFreeChart requires a range where lower <> upper. + +2011-10-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java, + src/main/java/de/intevation/flys/artifacts/states/DistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/RangeState.java, + src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Add whitespace after full stop in comments, minor doc improvements. + +2011-10-07 Ingo Weinzierl <ingo@intevation.de> + + flys/issue353 (W-INFO / Wasserspiegellagenberechnung, Diagramm) + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapted the process of collecting outs for Artifacts/Facets. We will now + call OutGenerator.doOut() for each Artifact and Facet - never mind if + the facet is activated (visible) or not. The OutGenerator should decide + on its own whtat to do with facets which are "marked" as _not_ visible. + + * src/main/java/de/intevation/flys/exports/OutGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/ReportGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/ATExporter.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Adapted the signature of OutGenerator.doOut(). There will be a new + boolean parameter "visible" that determines if the facet specified in + this method is visible for this output or not. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Now, + that we walk over every Artifact/Facet, we are able to collect min/max + data for all axes. We store these information and use them to set the + ranges of x and y axes. The result of this: a chart can have proper axes + set without any data in it. + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Use + min/max ranges stored while calling doOut() for each Artifact/Facet + instead of fetching those information from chart's Datasets (which could + be null). + +2011-10-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/Formatter.java: Changed the max + number of digits for AT exports from 0 to 2. + +2011-10-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ATWriter.java: Get rid + of buggy first line code. + +2011-10-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + fixed flys/issue201 + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Replace >= with > in km index lookup because last km was not found. + +2011-10-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + fixed flys/issue177 + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Revert rev2245. Code works fine now! :-) + +2011-10-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: Stores a + list of XYTextAnnotations instead of FLYS specific Annotations. This + makes this class suitable for other annotation types as well. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java: + Both facets' getData() will now return an instance of FLYSAnnotation. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java: + Create XYTextAnnotations used to instantiate an object of + FLYSAnnotation. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Removed the code to add annotations to the plot. This task is general + enough to move this code to parent class. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Instances of this class are now able to store - besides first and second + axes datasets - a list of annotations. This annotations are added to the + plot after the datasets have been added. To support LegendItems for + those annotions, it was necessary to create a the LegendItemCollection + by ourself. This work is done while applying the themes for each series + in the chart. + +2011-10-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Removed code duplication of guessWaterIncreasing() + + * src/main/java/de/intevation/flys/artifacts/model/WKms.java(allKms, allWs): + Added methods to fetch all kms and all ws. + + * src/main/java/de/intevation/flys/utils/DataUtil.java: Generalized to + get WKms as arguments. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java, + src/main/java/de/intevation/flys/artifacts/model/WQ.java: Implements + the extended WKms interface. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Uses the generalized DataUtil.guessWaterIncreasing(). + +2011-10-05 Ingo Weinzierl <ingo@intevation.de> + + flys/issue347 (W-INFO / Wasserspiegellagenberechnung, Längsschnittdiagramm) + flys/issue303 (Keine Streckenfavoriten, wenn nur Q im Längsschnittdiagram ausgewählt) + flys/issue353 (W-INFO / Wasserspiegellagenberechnung, Diagramm) + + * src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java: New. A + wrapper for Annotations which allows us to provide a description for a + set of annotations. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java: + The getData() will now return an instance of FLYSAnnotation that wraps + the Annotations returned by the AnnotationArtifact. The lebel of + FLYSAnnotation is the description of this Facet. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Modified the way to add Annotations. We will no longer create an empty + series to support a LegendItem for a set of Annotations, but we will add + a LegendItem manually to the LegendItemCollection of the plot. In + addition, we are now able to display annotations if one of the two + y-axes are missing. If there are no y-axes existing, we are not able to + display annotations yet. + +2011-10-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Lifted the wrong point. Now all backjump corrections look fine. :-) + +2011-10-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Fixed bugs and make use of a cache for annotations now. + +2011-10-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Worked on flys/issue31 + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Simplified the code a lot. Needs testing. Maybe flys/issue31 is gone + +2011-10-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Fetch the WstUnit value from river - the Wst itself no longer supports a + Unit iself. + +2011-10-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java, + src/main/java/de/intevation/flys/utils/DoubleUtil.java: Moved some generic + double array code to DoubleUtil. + +2011-10-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/utils/DoubleUtil.java (interpolateSorted): + Added code to linear interpolate double values in a sorted array. + Keys and values are given as double arrays. Keys need to be sorted. + +2011-10-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Removed superfluous imports. + +2011-10-04 Ingo Weinzierl <ingo@intevation.de> + + flys/issue330 (Dauerlinie kann nicht berechnet werden) + + * src/main/java/de/intevation/flys/artifacts/model/Calculation3.java: + Add a problem if no data was found for duration curves. + +2011-10-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/themes/Theme.java, + src/main/java/de/intevation/flys/themes/DefaultTheme.java: Added + getter/setter methods to provide a facet (string) and index (int). Both + values are written as attribute to the Theme's XML representation. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Set the "facet" and "index" values of themes. + +2011-10-04 Ingo Weinzierl <ingo@intevation.de> + + flys/issue346 (W-INFO / Anzeige der Höheninformation) + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Modified x and y axis title. The x axis title is now "RIVERNAME-km"; the + y axis title is now "W[WST_UNIT]" where WST_UNIT depends on the unit of + the WST. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Modified i18n expressions for + x and y axis of longitudinal section charts. + +2011-09-30 Ingo Weinzierl <ingo@intevation.de> + + flys/issue351 (W-INFO / Wasserspiegellagenberechnungen) + + * src/main/java/de/intevation/flys/utils/DoubleUtil.java: Modified the + explode() function that returns a list of values specified by min, max + and an interval. If the last value, determined by the interval, is + bigger than the max value, it is not included in the result list. + +2011-09-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + flys/issue334 (Querprofil-Diagramm: Ausgabe dieses Diagrammtyps + möglich, obwohl WSP Berechnung keine Ergebnisse liefert) + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + (compute): Add Facets regarding CrossSections only if data available. + +2011-09-29 Ingo Weinzierl <ingo@intevation.de> + + flys/issue176 (Diagramm: Benennung eines Abflusses bei gewählter Höhe am Pegel) + flys/issue349 (W-INFO / Wasserspiegellagenberechnung, Längsschnittdiagramm) + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Create titles for W and Q waterlevel facets with proper fractions. + +2011-09-30 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + (createStaticData, getLabels): Create proper labels for differences. + +2011-09-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue244 (WINFO: Export von AT-Dateien im ersten Teil unterschiedlich) + flys/issue332 (W-INFO / Berechnung Abflusskurve, Export, FLYS 2.5) + + * src/main/java/de/intevation/flys/exports/ATWriter.java: Due to a rounding + issue the w's of the first line underun the minimal w of the curve at times. + An extra test was introduced to suppress the output of the q's of the wrong w's. + +2011-09-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Use StringUtil.wWrap , fix wrong loop, minor refac and cosmetics. + +2011-09-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + Extracted/use StringUtil.wWrap . + +2011-09-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java: + Log the gauge which has been determined. + +2011-09-28 Ingo Weinzierl <ingo@intevation.de> + + flys/issue332 (W-INFO / Berechnung Abflusskurve, Export, FLYS 2.5) + + * src/main/java/de/intevation/flys/exports/ATExporter.java: Store the + master Artifact which is set via setMasterArtifact(). This is required + for meta information used while preparing the header row of AT exports. + + * src/main/java/de/intevation/flys/exports/ATWriter.java: Print a header + row into the AT export for being compatible with desktop FLYS. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added header row for AT + export files. + +2011-09-28 Ingo Weinzierl <ingo@intevation.de> + + flys/issue328 (W-INFO / ÃœSK: Auswahl der Wasserspiegellage / Auswahlunterstützung) + + * doc/conf/meta-data.xml: Added an out 'waterlevels' that might be used to + fetch user specific waterlevels (same as longitudinal sections, but + without Q facet). + In addition, the system specific datacage stuff is now fetched, when: + a) no user-id is given + b) a user-id is given and there is a parameter 'load-system' + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + If the label of the WQKms object specified by the waterlevel selection + begins with a "Q", the label is wrapped into a "W()", e.g. "W(Q=1200)". + +2011-09-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Made + feed() able to remove existing data items from Artifact's data pool. + Therefore, the value for the item which should be removed needs to an + empty string. + +2011-09-28 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Extracted StringUtil.unbracket from WaterlevelSelectState.strip. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + Extract and use StringUtil.unbracket, minor doc. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Changed access of getCurrentState() from protected to public. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: We + use the configured Outputs instead of the actuel Outputs of an Artifact + to make recommendations, now. This has the bad side effect of giving + recommendations for Outputs that we might _NOT_ be able to produce. But + otherwise, we would not be able to give recommendations for states with + long calculation times that start background threads for calculation (as + WSPLGEN caluclations does). + +2011-09-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Enable "auto-scaling" axis for waterlevels in WDifference-plots. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + (createSecondaryAxis, zoomY): Refactored to allow modification in + siblings. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + (createSecondaryAxisRange): Override to achieve expected behavior. + Also adjusted label. + +2011-09-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + In W-Difference Calculation, respect indices of selected facets. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + (computeAdvance): Respect index of selected facets. + +2011-09-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue317: (Querprofil-Diagramm: Referenzen auf CrossSectionApp entfernen) + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed dependency to demo app. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Refactored to use logic from the models. + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Moved some logic from the demo app to this model. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: New. Code + from FloodMapState moved to its own class with the intent, to use it in + classes different from FloodMapState. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Removed the inner class FacetCreator. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: Stores + an instance of FacetCreator. + NOTE: Maybe we should move the WSPLGEN parameters into an own class + which might be serializable. + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: Use the + FacetCreator instance stored in the WSPLGENJob to create a new WSPLGEN + facet if the calculation was successfully (without errors). Finally, the + facets of FacetCreator are added to the Facet list of the FLYSArtifacts. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Put Artifact in background mode first before starting WSPLGEN, otherwise + a very fast errors (call CallContext.afterBackground() before Artifact is + in Background mode) might lead to an inconsistent state. + + * src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java: Repaired + broken error num parsing. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java: Track + critical errors as well (improved regular expression for errors). + +2011-09-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * ChangeLog: Fixed whitespace usage. + +2011-09-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/RiverService.java, + src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java + src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Removed superfluous imports. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + flys/issue68 (Diagramm: Werte an der Y-Achse benötigen i18n) + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Added a + method to retrieve the current/preferred locale specified by CallMeta. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Introduced two methods localizeDomainAxis() and localizeRangeAxis(). + Both methods of this class override the NumberFormat used to format axes + numbers. Those methods are called by localizeAxes() - which has private + access - for each domain and range axis of the current XYPlot. + +2011-09-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Number of cached annotations was much + to low. + +2011-09-27 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved w-differences diagram generation where multiple differences + can be shown. + + * src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java: + New facet type. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Employ new DifferenceCurveFacet, return CalculationResult that can + store more than one WKms. + +2011-09-27 Ingo Weinzierl <ingo@intevation.de> + + flys/issue320 (ÃœSK:Mapserver hat Probleme beim Shapefilepath mit "../" im Pfad) + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Use + File.getCanonicalPath() to substitute "../" in shapefile directories. + +2011-09-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + The extent of the WSPLGEN result layer is now specified by the extent of + the CrossSectionTracks that matches the start and end kilometer of the + WSPLGEN calculation. + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: New function + that creates the OpenLayers bounding box based on two Geometries. + +2011-09-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved w-differences diagram generation with included "absolute" + values. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Fixed one (of two) incorrect labels. + (doWaterlevelOut): Survive non-found gauge, fetch kilometer and w + instead of values for w and q. + +2011-09-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add positional-conflict-awareness when merging Facets for a + FLYSArtifactCollection. First come first serve. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + (writeFacets): First, sort incoming facets into 2 groups: + "genuinely new" and "already there", then for each new check + whether the position is already taken. If so, push "up" (position++) + until no conflict exists anymore. + +2011-09-26 Ingo Weinzierl <ingo@intevation.de> + + flys/issue296 (Karte: Bezeichnungen verbessern) + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + I18N of the WSPLGEN and barriers facets (WMS layers). + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added strings for the wsplgen + and barriers WMS layers. + +2011-09-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix (revert) access to position in ManagedDomFacet. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java: + (getPosition): Do not add prefix when querying position ("pos") + attribute, add a logger for faster future debugging. + +2011-09-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Squash positional conflict-bug. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + (mergeFacets): Removed, replaced in parts by pickFacet. + (pickFacet): New, return facet to be added to document. + Documentation added. + +2011-09-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Squash a bug about wrongly named "art:pos" attribute in ManagedDomFacet (was + "pos"). Added documentation from commit message. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java: + Added documentation (commit message with minor adjustments). + (getPosition, setPosition): Include PREFIX in attribute name. + +2011-09-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactoring, doc. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + (mergeFacets): Removed, replaced in parts by pickFacet. + (pickFacet): New, return facet to be added to document. + Documentation added. + +2011-09-23 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, docs. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Documentation added. + +2011-09-22 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Subclasses the FLYSService now - this should improve the database + connection handling. + +2011-09-22 Bjoern Schilberg <bjoern.schilberg@intevation.de> + + * doc/mapserver/mosel-mapfile.map: + Full blown mosel wms mapfile. + +2011-09-22 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/FLYSService.java: + New. A subclass of DefaultService which is used in FLYS to init and + shutdown database connections. + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java, + src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java, + src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + Centralized the initialization and shutdown of database connections. + These services now subclass FLYSService which handles the database stuff. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: The + current database connection is not closed here - this is done in a + Service or in the CallContext. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: It's + not necessary to create new database connections here. We already have + an existing connection which is initialized by CallContext. + +2011-09-22 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DistanceOnlySelect.java: + Override validate() of parent classes to suppress "step" validation + which is not present in this state. + + * src/main/java/de/intevation/flys/artifacts/states/RangeState.java: Added + new method validateBounds() which really just validates a boundary + without "step" parameter. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added WaterlevelArtifact to accompany WINFOArtifacts in WDifferencesPlots. + + * src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java: + New WaterlevelArtifact. + + * doc/conf/conf.xml: + Added configuration for WaterlevelArtifact configuration (path to state-xml) + waterlevel-factory. + + * doc/conf/artifacts/waterlevel.xml: + New, trivial state description for Waterlevelartifact. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java: + New, only state for WaterlevelArtifact. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, docs. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Cosmetics, documentation. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added WaterlevelOut-processing ability to WDifferencesCurveGenerator. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Process LONGITUDINAL_W facets. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved WDifferenceState in preparation to be able to deal with multiple + pairs for differences. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Prepare multiple-pairs-case. + +2011-09-21 Ingo Weinzierl <ingo@intevation.de> + + flys/issue315 (Ãœberschwemmungsfläche: String bei Streckenauswahl) + + * doc/conf/artifacts/winfo.xml: Added a new state for floodmap's range + input. This state will accept a km range only, there is no step width. + + * src/main/java/de/intevation/flys/artifacts/states/DistanceOnlySelect.java: + New. The state which is used to enter a km range with step width. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, improved debug output, doc. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Improved debug output. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java: + Added documentation. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Removed commented code. + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: + Whitespace cosmetics. + +2011-09-21 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Avoid NullPointerException when drawing XYChart without data. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Guard calls to dataset to avoid NullPointerException. + +2011-09-21 Ingo Weinzierl <ingo@intevation.de> + + flys/issue325 (FLYS Client: Auswahl des DGM zeigt numerischen Wert an) + + * src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java: Write + a better label for the selected DEM into the static DESCRIBE. Use the + name of the DEM file as label instead of the database id. + +2011-09-16 Bjoern Schilberg <bjoern.schilberg@intevation.de> + + * doc/mapserver/fontset.txt: + Added initial font set for km_annotation layer. + * doc/mapserver/symbols/symbols.sym: + Added square symbol for km and fixpoint layer. + * doc/mapserver/saar-mapfile.map: + Adjust styling in the flys karte-archiv way. + +2011-09-19 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 2.5 + + * Changes: Prepared changes for release. + +2011-09-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Removed + needless imports. + +2011-09-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Improved datacage configuration for DEMs. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Query DGMs by the given ID in the FLYS data pool - not by given range + values. + +2011-09-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Added a section for DEMs to the floodmap + section. + +2011-09-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix build. + + * src/main/java/de/intevation/flys/artifacts/state/WDifferencesState.java: + Fix build. + +2011-09-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Take a given WaterlevelPair-String, load artifact and plot the diff. + + * src/main/java/de/intevation/flys/artifacts/state/WDifferencesState.java: + Load correct artifacts. + +2011-09-16 Bjoern Schilberg <bjoern.schilberg@intevation.de> + + * doc/mapserver/*: Added inital mapserver configuration files. + +2011-09-16 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data.xml: Moved the system specific configuration into a + macro to the top of the configuration document. Call this macro at the + end of the user specific part and in the part that should contain the + system specific stuff only! + +2011-09-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Defined createItem() here and adapted some method signatures, because I + need the CallContext deeper in code than expected. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + Write the name of the selected waterlevel into the static DESCRIBE. + + * src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java: + Adapted method signatures that have been changed in DefaultState. + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Removed method createItem() which is now defined in the upper class + DefaultState. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added string for selected + waterlevel that is displayed in static UI. + +2011-09-16 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added state label for + waterlevel selection. + +2011-09-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + Validate incoming data string and strip brackets. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Fetch waterlevel data from external Artifact if existing. If no external + Artifact is specified that provides waterlevel data, we gonna try to + fetch it from the current Artifact. + +2011-09-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + Removed needless import which caused compile errors. + +2011-09-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added a transform() method. This method should be used to transform + input data in form of a string into a better data structure. This state + provides a simple implementation which just returns a StateData object + that contains exactly the input string. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Transform + input strings using DefaultState.transform() before they are added to + its data pool. + +2011-09-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Made collection solid for the case if it has no Artifacts. + +2011-09-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Fetch Artifact + from ArtifactDatabase properly. Write better error logs if that process + fails. + +2011-09-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Extend WDifferences branch to have calculations in dedicated, new state. + + * doc/conf/artifacts/winfo.xml: Added new State and Transition in + WDifferences-branch. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java: + New state. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Specify to not take input, prepare getting other facets. + +2011-09-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java: This + state now desires the UIProvider 'dem_datacage_panel'. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java: + New. This state is used to define the desired UIProvider + 'wsp_datacage_panel'. + + * doc/conf/artifacts/winfo.xml: Added a new way to start a WSPLGEN + calculation when choosing the calculation type 'floodmap'. + +2011-09-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: Merge + facets only if their name AND their owner artifact are equal. + +2011-09-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Partial Fix flys/issue304 (3) (Baseline). + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Show Baseline in WDifferencesPlot. + +2011-09-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue310 (cross-section theme). + + * doc/conf/themes.xml: CrossSection-Themes: profile thin, water blue. + +2011-09-14 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue310 (cross-section theme). + + * doc/conf/themes.xml: CrossSection-Themes: profile thin, water blue. + +2011-09-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Add an quick and simple error to the report if an error occured while + WSPLGENJob creation. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added error messages for + WSPLGEN job creation errors. + +2011-09-13 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix crash when drawing StickyAxisAnnotation when no range was given. + User-directed issues remain ( flys/issue303 ). + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java + (draw): + Guard access to domainAxis, rangeAxis and the corresponding ranges. + Warn and exit if any was null. + +2011-09-13 Ingo Weinzierl <ingo@intevation.de> + + flys/issue290 (Karte: Eingabe von Differenzen zw. WSP und Gelände findet + keine Ausprägung in der Karte) + + * doc/conf/mapserver/wsplgen_class.vm: Added styles for DIFF attribute. + + * doc/conf/mapserver/mapfile.vm: Set debug default to '5'. + +2011-09-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Add a first WSPLGEN status message (notifies the user about a + queued job) after the job has been added to the Scheduler. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added english and german + status message text. + +2011-09-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Write + shapefiles only if there are features for it existing. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + A WSPLGEN facet is only created, if the calculation was successfully + added to the Scheduler. A barrier facet is only created if the WSPLGEN + calculation has been added to the scheduler AND if there are digitized + geometries existing. + +2011-09-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Copied and slightly modified implementation of guessWaterIncreasing from + WQKms to (new) DataUtils. Accidentally commited usage in last commit, to + correct orientation of diagram (invert x axis). + + * src/main/java/de/intevation/flys/utils/DataUtils.java: + New file with guessWaterIncreasing implementation from WQKms, + slightly adjusted. + +2011-09-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java: + Cosmetics. + +2011-09-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added CSV Export for W-Differences. + + * doc/conf/conf.xml: Added Exporter. + + * doc/conf/artifacts/winfo.xml: Removed transition over distances + state, added export outputmode and facet. + + * src/main/java/de/intevation/flys/exports/WDifferencesExporter.java: + New, CSV-Exporter for WDifferences. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Add export facet. + +2011-09-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: + Cosmetics, docs. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + Cosmetics. + +2011-09-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Sourced the code to append a concrete data item to the static DESCRIBE + part out to an own method (appendStaticData()). + + * src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java: + Override appendStaticData() to suppress the GeoJSON string to be + included in the static DESCRIBE. + +2011-09-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Removed needless imports. + +2011-09-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CalculationMessage.java: + New. A subclass of Message (in the Artifacts system). It stores a + string message and a progress (in form of step x/y). + + * src/main/java/de/intevation/flys/wsplgen/JobObserver.java: The observer + now writes background messages into the artifact system using the + CallContext.addBackgroundMessage(). We use instances of + CalculationMessage here, that makes the WINFOArtifact able to put + progress information into the Artifact's DESCRIBE as well. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Write + status message and progress information into the DESCRIBE if the + Artifact has started a background process. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue280 . + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Do not draw boxes around annotations. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix flys/issue279 . + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Fix behaviour in various thinkable malconditions. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Made one case of cross section fetching more robust. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix Facet name and Legend of W-Differences, also insert state to specify + distance. + + * doc/conf/artifacts/winfo.xml: Add additional transitions to walk over + distances state. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + Set facets description. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + Take facets description as legend. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added configuration to kick-in w-differences branch of winfo. + + * doc/conf/conf.xml: Register new (w-differences) OutputGenerators. + + * doc/conf/artifacts/winfo.xml: Register new state and transitions. + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Added new (w-differences) calculation mode. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveInfoGenerator.java: + New file, implementing naive approach to display w-differences + (accidentially omitted in last commit). + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added very stubby WDifferences State/OutGenerator for WINFOArtifact. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added w_differences facet type. + + * src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java: + New file, implements naive approach to calculate w-differences (of + calculations identified by hardcoded uuids!) and register respective facet. + + * src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java: + New file, implementing naive approach to display w-differences. + +2011-09-09 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Implement getArtifact(uuid,context) in FLYSUtils. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java (getArtifact): + Added implementation, partially resolving a TODO. Added logger instance. + +2011-09-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java: + New. This sublcass of Calculation saves warnings and errors that occur + while WSPLGEN is running. + Note, that the interface of this class doesn't exactly apply the interface + of Calculation. Maybe, we should generalize this interface! + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: Stores + an instance of WSPLGENCalculation now. We use this instance to save + warnings and errors. + + * src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java: Use the + WSPLGENCalculation to save errors and warnings. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENReportFacet.java: + New. This facet is used for WSPLGEN reports. It stores an instance of + WSPLGENCalculation which saves ERRORS and WARNINGS that occur while + WSPLGEN execution. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Create a WSPLGENReportFacet for WSPLGEN reports. + + * doc/conf/conf.xml: Added an OutputGenerator 'report' for WSPLGEN + reports. + + * doc/conf/artifacts/winfo.xml: Added an output 'report' for WSPLGEN + reports. + +2011-09-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/math/WKmsOperation.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Cosmetics, docs. + +2011-09-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/JobObserver.java: Small + adjustments that makes it easier to subclass this observer. + + * src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java: New. A + sublcass of JobObserver which analyses the WSPLGEN output for errors and + warnings. + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: Use + JobObserver and ProblemObserver to track the whole WSPLGEN output and + print number of errors/warnings to log output. + +2011-09-08 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added translation of w_differences. + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages.properties: + Added "w_differnces" translation. + +2011-09-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Appended + a new attribute 'background-processing' to the DESCRIBE of this + Artifact. Its value is 'true' if this Artifact has started a background + thread which has not finished yet - otherwise it is 'false. + +2011-09-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java, + src/main/java/de/intevation/flys/utils/GeometryUtils.java: Moved the + code to determine the extent of a river based on its axis to + GeometryUtils. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Determine the extent of the selected river and set the WMSLayerFacet's + extent attribute. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added Themeing support for CrossSection Diagrams. + + * doc/conf/themes.xml: + Added new themes and mappings, slightly modified longitudinalsection + theme. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + In CrossSection Diagram fix subtitle to display the km of which the data is + actually displayed (maybe contrasting users wish). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + (getCrossSectionSnapKm): New method to fetch the actual km of crosssection. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Add correct km to charts subtitle. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix various display-issues like i18n in cross-section diagram. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Set description of facets to expected values. + + * src/main/java/de/intevation/flys/artifacts/exports/CrossSectionGenerator.java: + Fix i18n of chart title. Set subtitle to expected value, pass facets + description to StyledSeries to see expected legend. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics, resolved refactoring todo. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java + (compute, computeAdvance, computeFeed): Refactored, extracted method, + resolving duplicate code and TODO. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix waterline "calculation" at given km. Chosen approach is + "head-through-wall". + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Some refactoring to do the same calculation twice easier and be able + to "cross" waterline against correct profile data. + + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix setting of kilometer for profile (not yet waterlevel) of cross section + diagram. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + (getCrossSectionData): Respect corss_section.km data; do naive linear + search for profile data for this km. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + Declare a ComputeType. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Implement computeFeed. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Minor cosmetics. + +2011-09-07 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java, + src/main/java/de/intevation/flys/artifacts/model/DataFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/state/DefaultState.java: + Cosmetics, docs. + +2011-09-06 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/barrier_polygons_class.vm, + doc/conf/mapserver/barrier_lines_class.vm, + doc/conf/mapserver/wsplgen_class.vm: Default Mapserver styles for + barriers and WSPLGEN results. Those styles are only used as long as we + don't have map specific themes (as already used in charts). + + * doc/conf/mapserver/layer.vm: Implements a fallback mechanism for styling + barrier lines/polygons and WSPLGEN results. + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Added a + getStyle() method that currently returns "null". This method needs to be + implemented when map themes are introduced. + +2011-09-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Renamed + some attributes to make their job in the mapfile more obvious. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + new facet type for barriers. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: Add + a facet for the barriers layer. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Parse + barriers (lines and polygons) and create two new layers for each type - + those layers are grouped. + + * doc/conf/mapserver/layer.vm: Renamed attribute based on changes in + LayerInfo and added support for Group-Layers. + +2011-09-06 Raimund Renkert <raimund.renkert@intevation.de> + + * doc/conf/conf.xml: + Added driver to database configuration for use with postgresql. + +2011-09-06 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/mapfile.vm: Removed FONTSET attribute and set quotes + for SHAPEPATH. + +2011-09-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENFacet.java: + Removed. We gonna use the WMSLayerFacet until now. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Add a WMSLayerFacet after we triggered the Scheduler to start a WSPLGEN + calculation. + +2011-09-05 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/mapserver/layer.vm, + doc/conf/mapserver/mapfile.vm: Small bugfixes and style improvements. + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: Trigger the + MapfileGenerator after a WSPLGEN job has finished regardless if it has + been finished successfully or not. + +2011-09-05 Ingo Weinzierl <ingo@intevation.de> + + * pom.xml: Added Apache Velocity 1.7 for templating support. + + * doc/conf/conf.xml: Added config options for mapserver/template relevant + stuff. + + * doc/conf/mapserver/mapfile.vm, + doc/conf/mapserver/layer.vm: New. A default mapfile template and a + template used for layers. + + * src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: New. + This class is used while reading WMS layer relevant information from + filesystem. + + * src/main/java/de/intevation/flys/utils/MapfileGenerator.java: New. This + thread is used for creating mapfiles for Mapserver. The MapfileGenerator + runs in daemon mode (own thread) and creates mapfiles based on WMS + layer relevant information read from filesystem. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java, + src/main/java/de/intevation/flys/utils/FLYSUtils.java: Moved shapefile + specific XPath expressions from FloodMapState to FLYSUtils which is a + better place to use it in other classes (as MapfileGenerator). + +2011-09-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: + Bugfixed broken attribute assignment. + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: Call + CallContext.afterBackground() after a WSPLGEN job has finished to remove + the background lock from Artifact. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Call CallContext.afterCall(BACKGROUND) to lock the Artifact for + background processing. + +2011-09-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/wsplgen/JobExecutor.java: New. This + class is used to start WSPLGEN for a specific WSPLGENJob. The System + property "wsplgen.bin.path" tells the JobExecutor where the WSPLGEN + binary is placed (which means in general, the property points to the + 'wsplgen.exe'). + + * src/main/java/de/intevation/flys/wsplgen/Scheduler.java: New. This + scheduler currently allows to start just a single WSPLGEN Thread. All + WSPLGEN calculations should be started using Scheduler.addJob(). + + * src/main/java/de/intevation/flys/wsplgen/JobObserver.java: New. This + thread reads log messages from WSPLGEN and listens for specific + messages. It should be used to update status messages of the WSPLGEN + calculation that is currently running. + There is a System property that tells the JobObserver to log all WSPLGEN + output to log4j: enable WSPLGEN output with "-Dwsplgen.log.output=true". + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: Added + the FLYSArtifact, the current working directory and the CallContext. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Use the Scheduler to start new WSPLGEN calculations. + +2011-09-02 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add CrossSectionInfoGenerator. + + * src/main/java/de/intevation/flys/exports/CrossSectionInfoGenerator.java: + New, trivial implementation of CrossSectionInfoGenerator. + + * doc/conf/conf.xml: + Register CrossSectionInfoGenerator. + +2011-09-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cleanups of CrossSection*. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + New methods to retrieve name of utilized CrossSection. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Cleanup, get rid of copied unused method, documentation and more sensible + translations. + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages.properties: + Added cross_section* translations, also cleanups. + +2011-09-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Set the "typ" attribute of lines and polygons in barrier shapefiles. + +2011-09-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Set the Z values of line and polygon barrier geometries. Both barrier + shapefiles will contain 3D geometries now. + +2011-09-01 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Get real data to display in CrossSection (although ignorant of + parameterization), making use of the showcase code of the CrossSectionApp- + Standalone application. + + * doc/conf/artifacts/winfo.xml: Add new facet (~waterline) to state/out. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + New methods to get relevant data. So far just takes the first value of + everything and assuming a waterlevel at 130m. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + New Facet responsible of water level in cross section. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Made some functionality publicly and statically available. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + Update call. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added new + Facet type. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Added new Facet to out. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Respect new facet and facets data. + +2011-09-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Close an open + shapefile transaction and catch exceptions which are thrown while + shapefile creation here. If there occured an error, this functions + returns FALSE, otherwise TRUE. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Removed exception handling while shapefile creation - this is done in + GeometryUtils now. + +2011-09-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Renamed the file for WSPLGEN required waterlevels to "waterlevels.wst". + WSPLGEN did not work with the former "waterlevels.txt" file. + +2011-09-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: New static + function that builds new SimpleFeatureTypes with additional attributes. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Write attributes "ELEVATION" and "KILOMETER" into the crosssection + tracks shapefiles. + +2011-08-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a method + stub that should return a FLYSArtifact based on a given UUID. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Write the selected WST file for WSPLGEN. Note, that this is the WST file + of the current WINFO artifact. Furthermore, there is currently no way + for the user to select a column from WST file, so we currently use the + column that is written to WST file at first. + +2011-08-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Changed + the parameter order of a compute(...) method. This makes me able to call + this without a hash value. + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java: + Adapted the parameter order of the compute() call (see above). + +2011-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + More bones to CrossSection sceleton. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java: + New, yet trivial implementations of Factory and Facet for CrossSections. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Add new CrossSection- (instead of Default-)Facet. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Adjusted to use (touch) new Factory and Facet. + +2011-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Cosmetics. + +2011-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Cosmetics. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + Removed obselete imports. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Removed obselete imports, whitespaces. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Whitespaces, docs. + +2011-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Fix translations of Main Values Facets. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Do acrobatics to keep state transient but get translated title. + + * src/main/java/de/intevation/flys/artifacts/MainValuesQFacet.java, + src/main/java/de/intevation/flys/artifacts/MainValuesWFacet.java: + Changed constructor to get description (which is then already be translated) + dynamically, adjust deepCopy. + + * src/main/java/de/intevation/flys/states/StaticState.java: + Adjust constructor accordingly. + +2011-08-31 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Add sceleton for CrossSection outs. + + * doc/conf/artifacts/winfo.xml: + Added new output mode to respective state of winfo artifact configuration. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Add new Dummy-Facet in state. + + * doc/conf/conf.xml: + Registered new OutputGenerator. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new CROSS_SECTION type. + + * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java: + New, stubby skeleton for an CrossSectionGenerator. + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages.properties: + Added cross_section translation, also cleanups (e.g. main values). + +2011-08-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: Marked + required parameters with a comment. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Export floodplains (german 'Talaue') to shapefile and write its file + path into the WSPLGEN job. + +2011-08-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Search for a DGM that fits to the current river and km range and write + its file path into the WSPLGEN job. + +2011-08-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Improved + exception handling: exceptions are catched in GeometryUtils now. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Write river axis and crosssections to shapefiles and save shapefile + pathes in WSPLGENJob. + +2011-08-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Use the coorect SRID for reading GeoJSON and writing line/polygon + shapefiles. + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: Use a + concrete coordinate system while feature type creation. + +2011-08-30 Ingo Weinzierl <ingo@intevation.de> + + * pom.xml: Added GeoTools 2.7.2 dependencies for Shapefile, GeoJSON and + EPSG support. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: Store + 'LIN' parameter in a list now. A WSPLGEN parameter might contain many + LINs. + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: New functions + to create FeatureTypes and to write shapefiles. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Write user specified barriers into a shapefile placed in the artifact + directory. + +2011-08-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function + that extracts the SRID defined in the global configuration file for a + given river. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Removed the code that extracts the river SRID - use FLYSUtils instead. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use FLYSUtils.getRiver instead of WINFOArtifact.getRiver. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Use FLYSUtils.getRiver instead of WINFOArtifact.getRiver. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use FLYSUtils.getRiver instead of WINFOArtifact.getRiver. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Use FLYSUtils.getRiver instead of WINFOArtifact.getRiver. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Commit accidentally omitted result of refactoring (WINFO/FLYSUtils/getRiver). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed implementations of getRiver, update calls to use FLYSUtils. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Interpolate Q main values, generate interpolated W main values on the fly from + Q main values. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + (getGaugeDatum): removed, obsolete + (getLocation): new, gets location + Use WstValueTable to look up interpolated Qs of MainValues. In absence of + the same functionality for Ws, generate W Main Values from Q Main Values. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Use new helper class FLYSUtils, minor refactorization. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Use new functionality of helper class, convenience of FLYSArtifact. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Refactored to use new Helper class FLYSUtils, moved getRiver-functionality + in there. + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java (getRiver): + New function to retrieve river of an artifact, slightly modified from + WINFOArtifact. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Removed implementations of getRiver, update calls to use FLYSUtils. + +2011-08-29 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Minor cosmetics. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Resolved a TODO. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Added some documentation. + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Minor cosmetic. + +2011-08-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data.xml: Made it Oracle compatible. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java: + If running in debug mode log executed statements. + Helps debugging Oracle connections. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Set some WSPLGENJob parameters which are stored at FLYSArtifact. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/FLYSUtils.java: New. This helper + class should provide some basic FLYS stuff. Currently, there are functions + that return the km range/location. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed + the methods that return the km range/locations. This is implemented in + FLYSUtils now. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: Adapted + the WINFO method calls to retrieve the km range/locations - call + FLYSUtils now. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: New method + to destroy a single state. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Cosmetic, remove debug output and comments, minor style adjustments. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added limited themeing-support for MainValues. + + * doc/conf/themes.xml: + Added Q/W-MainValues themes. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Added limited theming support, add legend entry for main values. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added a configuration node that points to the directory + where shapefiles should be stored in. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java: New. + This class is used to save/write the parameter for a WSPLGEN calculation. + WSPLGEN's *.par files are written using the toFile() method. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + A directory for all WSPLGEN stuff is created in computeAdvance() - those + directory and all its contained files are removed in endOfLife(). + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/utils/ThemeUtil.java: + New Util to work with theme-related stuff. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Use NamedDoubles instead of MainValues, try to adjust scale of Ws. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Use NamedDoubles instead of MainValues, generalize annotation handling, to + allow easier reusability and themeing. + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Added convenience constructor, exemplary switch on bordered text. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/meta-data.xml: + Recommend MainValues for Computed discharge curves. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + New NamedDouble class which implements a <String,double>-pair. + + * src/main/java/de/intevation/flys/artifacts/model/NamedDouble.java: + New, implementation of a double with a string or vice versa. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Call + State.endOfLife() for all States when endOfLife() of the Artifact is + called. + +2011-08-26 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Also plot "W"-MainValues (on vertical axis), take correct parameters, but + do not convert to correct scale (cm vs NN+m). + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Naive attempt at allowing the vertical axis to be sticked at. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Store Q and W MainValues separately, add them to plot as annotations. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Serve the MainValues, parameterized on river and location, Q and W. + Removed Facet-implementation. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Updated Facet Types. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java: + src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java: + New, trivial facets, extracted from MainValuesArtifact. + +2011-08-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Call + State.endOfLife() of each State that is no longer in the queue of the + artifact when this artifact steps back to a previous state. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Plot MainValues delivered by MainValuesFacet in much the same ways than + Annotations in LongitudinalSection plots. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Prepare further differentiation between Annotations that stick to X or Y- + Axis, copied some positioning logic into StickyAxisAnnotation + implementation. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Minor cosmetics. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added MainValue-Fetching-Capabilities to MainValuesArtifact. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java + (initialize, getMinValues): + Let MainValuesArtifact return "real" MainValues, although ignorant of all + parameterization. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java + (MainValueFacet): + Improved and straightened implementation, added code-Annotations and Todos. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java + (MainValueFacet): + Improved and straightened implementation, added code-Annotations and Todos. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java + (getState): + Resolved multiple creation of state (yet not very clean). + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Cosmetics, docs. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Cosmetics. + +2011-08-25 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added new (MainValues) Facet-Type. + +2011-08-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Added a method that returns a River object based on its database id. + + * src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: The + data that is required for this artifact is fetched from database instead + from a Master-Artifact. The creation of static artifacts should use + database ids instead of cloning a Master-Artifact. + +2011-08-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Removed needless imports. + +2011-08-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added configuration for factory and rule for MainValueArtifacts. + + * doc/conf.xml: + Add a mainvalue factory to serve MainValueArtifacts. + + * doc/conf/meta-data.xml: + Recomment mainvalue artifact when computed_discharge_curve can be put out. + +2011-08-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Let MainValuesArtifact have a state, outputmode and facet. + + * src/main/java/de/intevation/flys/artifacts/states/StaticState.java: + New, a non-abstract DefaultState. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Progressed with implementation, use StaticState to hook output modes and + facet in; use (Static)FLYSArtifact implementation. + +2011-08-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Smaller cosmetics. + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Cosmetics in comments. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Added @Override annotations. + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: + Use brackets to improve readability of ternary operator. + +2011-08-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data.xml: Use "ids" in user specific part, too. + +2011-08-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data.xml: s/db-ids/ids/g to unify system and user specific + loading. + +2011-08-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Extracted access to state and states in order to have fewer places to + modify when going for single/trivial state- artifacts. + +2011-08-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java: + Append the river's srid to the WMSLayerFacet. + +2011-08-24 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Minor fixes, ressurect Facet implementation as inner class. + +2011-08-24 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Moved the input of barriers one state + earlier where the scenario is selected as well. + + * src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java: + This state now desires the "map_digitize" UI provider and returns both + items "scenario" and "uesk.barriers" in the dynamic describe part. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Removed the UI provider and the computeFeed() which is no longer needed, + because there is no more user input in this state. + +2011-08-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Repaired broken xpath expressions (the config changed in one of the last + commits) and make use of the variable support in xpath expressions to + replace the rivername. + + * src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java: + Save the rivername while initializing this artifact. This is now + necessary, because each river can have its own background wms + configured. + +2011-08-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Repaired broken river-wms initialization. + +2011-08-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java, + src/main/java/de/intevation/flys/artifacts/model/DataFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java, + src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java, + src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java, + src/main/java/de/intevation/flys/artifacts/model/WSPLGENFacet.java: + Made facets cloneable with the right type. + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Removed superfluous imports. + +2011-08-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Declare the first artifact of an output as master artifact (artifacts + are ordered by their creation time). + +2011-08-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + Removed facet interface. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Make artifacts cloneable. TODO: Override deepCopy() in subclassed + states and facets. + +2011-08-23 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added the MapInfoService and adapted the floodmap + configuration. Now, each river can have its own background wms layer + defined. + + * src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java: + New. This service returns some basic information used to create maps for + a specific river. The name of the desired river needs to be defined at + "/mapinfo/river/text()". + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Adapted an xpath expression that points to the srid of a river in the + floodmap configuration (which changed). + +2011-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Build out/facet filter from XML document passed at creation time. + +2011-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Added some code to filter outs/facets by an optional positive list. + This is needed to only expose parts of the facets. This + is needed for artifacts which are loaded into a collection. + TODO: create the filter from the XML document passed at creation + time. + +2011-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Moved all + WINFO specific code to WINFOArtifact. FLYSArtifact is now only revolving + about state affairs. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Re-inserted + the specific stuff here. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Adjusted the casts. + +2011-08-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data.xml: Filter by outs in user template part. + +2011-08-22 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Defined an input value for the GeoJSON + string to save user defined barriers in the map. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + Added a computeFeed() method. In addition, this state now prefers the + "noinput" UI provider. + +2011-08-19 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Each river requires a SRID definition. This + definition is used to transform the river's geometries into the desired + projection. + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + This facets are able to save a SRID. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + The extent that is written into the WMSLayerFacet is determined by the + boundary of the geometry. + + * src/main/java/de/intevation/flys/utils/GeometryUtils.java: New. A + utility class that provides helper functions for geometries. Currently, + one function is defined, that creates a boundary string for OpenLayers. + +2011-08-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/RangeState.java: + Removed superfluous imports. + +2011-08-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Removed CallContext from state validation. It is not needed and hindered + the extraction of all out of an artifact if you don't have a + call context (like initial scan of datacage database). + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Extract all outs now. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java, + src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java, + src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/RangeState.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java, + src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Adjusted calls. + +2011-08-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Added lacalization of "Streckenfavoriten". + +2011-08-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Picky white-space cosmetics. + +2011-08-19 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added stub implementation of new MainValuesArtifact. + + * src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java: + New. Stub implementation for new MainValuesArtifact. + +2011-08-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fixed flys/issue262 + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + Unified user and system tempate. + Looks for "/artifact-database/metadata/template/text()" + in conf.xml. Defaults to "${artifacts.config.dir}/meta-data.xml". If user id is + given its the default connection for contexts. + + * doc/conf/conf.xml: Adjusted + * doc/conf/meta-data-system.xml, doc/conf/meta-data-user.xml: Deleted. + * doc/conf/meta-data.xml: Unified version of user and system template. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/App.java: + Adjusted the test program. + +2011-08-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fixed flys/issue260 + + * doc/conf/meta-data-user.xml: Uses master_artifacts view now. + +2011-08-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Added view master_artifacts to select + the master artifacts of the collections more easily. + To upgrade existing database: + + CREATE VIEW master_artifacts AS + SELECT a2.id AS id, + a2.gid AS gid, + a2.state AS state, + a2.creation AS creation, + ci2.collection_id AS collection_id + FROM collection_items ci2 + JOIN artifacts a2 + ON ci2.artifact_id = a2.id + JOIN (SELECT ci.collection_id AS c_id, + MIN(a.creation) AS oldest_a + FROM collection_items ci + JOIN artifacts a + ON ci.artifact_id = a.id + GROUP BY ci.collection_id) o + ON o.c_id = ci2.collection_id + WHERE a2.creation = o.oldest_a; + + TODO: Use the view in the templates. + +2011-08-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data-user.xml: Removed state filter because it was broken. + Simplified by joining two contexts. + +2011-08-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + Fix issues with lines of annotation when zoomed (wrong scale used). + +2011-08-18 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added legend for annotations to LongitudinalSectionDiagram. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Added a pseudo-dataseries/collection to employ existing infrastructure for + displaying localized label for Annotations (yet unthemed). + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: + Made label-string available for localization. + +2011-08-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Moved StickyAxisAnnotation into new package de.intevation.flys.jfree . + + * src/main/java/de/intevation/flys/exports/StickyAxisAnnotation.java: + Deleted/moved to src/main/java/de/intevation/flys/jfree/ . + + * src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java: + New/moved from src/main/java/de/intevation/flys/export/ , adjusted + package statement, made class public. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Added import statement for de.intevation.flys.jfree.StickyAxisAnnotation . + +2011-08-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Extracted and renamed CustomAnnotation to StickyAxisAnnotation. Also removed + needless imports. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/StickyAxisAnnotation.java: + Extracted class implementation CustomAnnotation and renamed to + StickyAxisAnnotation. + +2011-08-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Improved CustomAnnotations and rendering thereof, now including an + "axis mark" (little line at axis), also prepared possibility to put + annotations on Y-axis. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Improved CustomAnnotation to include marks on the axis and better spacing + from it. + +2011-08-17 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Implemented proof-of-concept collision-detection when drawing + CustomAnnotations (text only). + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + Pass a fresh ChartRenderingInfo-Object to createBufferedImage, such that + information can be collected while rendering. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Exploit the fact that XYTextAnnotation already registers drawn shape in the + ChartRenderingInfo if it exists and either an URL or tooltip is set. + Before drawing, calculate own shape and compare against already registered + shapes. + +2011-08-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Implemented (yet dummy) custom Annotation class. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Added implementation of yet dummy CustomAnnotation class. + +2011-08-16 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Slightly improved rendering of annotations. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Slightly improved rendering of annotations. Still no valid collision + detection. Annotations are drawn every 2 km; first come first serve. + +2011-08-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue191 + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java(longestIncreasingWRangeIndices): + Added a method to find the longest index range with increasing w values. + + * src/main/java/de/intevation/flys/exports/ATWriter.java: Export the longest + range of monotone increasing w values instead of the first one. + TODO: The first line of the export is still broken. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Removed superfluous import. + +2011-08-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java: + Resolved two TODOs: get Annotations of selected River, get "point" + Annotations only. + +2011-08-12 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added functionality to query range and point-annotations only to + AnnotationFactory. + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java + (getPointAnnotations, getAnnotationsBreadth): + New functions to query breadth and point-only annotations. + +2011-08-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + Added a development mode for recommendations. Enabled with + stetting system property 'flys.datacage.recommendations.development' to true. + When set the XML template are re-read if the timestamps of the + files have changed so you do not have to restart the server again and again. + + * doc/conf/meta-data-user.xml: Sort collections by creation time in descending order. + +2011-08-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Rather picky cosmetics only. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java, + src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java, + src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + End comments on a full stop, separate from closing '*/' by whitespace, + adjusted javadoc comments. + +2011-08-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Made Annotations visible in LongitudinalSection diagrams. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Register new Facet Type, let LongitudinalSectionGenerator include + Annotations in diagram (yet unfiltered and independent of river). + +2011-08-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml, + doc/conf/artifacts/annotation.xml, + doc/conf/meta-data-system.xml: + Added configuration for AnnotationArtifacts. + +2011-08-11 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + Added demo- implementation of a AnnotationArtifact and its Facet. + + * src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java, + src/main/java/de/intevation/flys/artifacts/states/AnnotationRiverState.java: + New. Initial version of an AnnotationArtifact and its State and Facet. + +2011-08-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Extended schema for artifacts and collections + to have creation times, too. + + To update existing databases: + + ALTER TABLE artifacts ADD COLUMN creation TIMESTAMP NOT NULL DEFAULT current_timestamp; + ALTER TABLE collections ADD COLUMN creation TIMESTAMP NOT NULL DEFAULT current_timestamp; + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Store creation times for artifacts and collections, too. + + * src/main/resources/datacage-sql/org-h2-driver.properties, + src/main/resources/datacage-sql/org-postgresql-driver.properties: + Adjusted SQL statements. + +2011-08-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Make it compilable again (BackendListener interface changed). + +2011-08-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data-user.xml: Added grouping element around w/q of each + longitudinal section artifact. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java, + src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java: + Added some debugging capabilities. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/ResultData.java: + Added isEmpty() method. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Now it is possible to nest <dc:elements> into other elements in the <dc:context> + body. This is useful and needed for grouping and repeating results. + +2011-08-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + User connection was cached, system was not. Lead to incorrect results. + +2011-08-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data-user.xml: Added <old_calculations> element + around old calculations. + +2011-08-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: + Cosmetic: Replaced usage of legacy java.util.Stack with java.util.Deque. + +2011-08-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data-user.xml: Use 'CAST(x AS uuid)' instead of 'x::uuid' + to be more compatible. + +2011-08-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + If given an artifact place its identifier into parameters passed to template. + Fixed swapped user/system connections if using the user template. + + * doc/conf/meta-data-user.xml: Recommend w/q facet from old calculations + if an artifact was given that represents a longitudinal section + "Laengsschnitt". + + TODO I: The template uses PostgreSQL specific UUID casts. + TODO II: We need to find a way only to recommend the master artifacts. + +2011-08-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Added a <dc:comment> tag to place comments in the meta data templates. + <!-- ... --> comments are copied through. + + * doc/conf/meta-data-user.xml: Added a simple test. + +2011-08-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Be a bit more tolerant about empty strings for UUIDs of artifact and user. + +2011-08-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Bring user specific meta data service to life. + + * doc/conf/conf.xml: There are now two templates to configure: + The system template (only the data from the backend) and the + user template (the datcage db and the backend db), + + * doc/conf/meta-data-template.xml: Deleted. + * doc/conf/meta-data-user.xml: New. The user specific template. TODO: Write it! + * doc/conf/meta-data-system.xml: New. The system template. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/NoneUserSpecific.java: + Deleted. + * src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java: + New. The logic to fill the templates. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + Adjusted to follow the new call signatures. + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Refactored. Removed the old code and only leave the new service. Following + XPaths are evaluated on the incomming document: + + "/art:meta/art:artifact-id/@value" The UUID of the artifact. Optional. + Used to fill the template enviroment. + "/art:meta/art:user-id/@value" The UUID of the user. Optional. + If given the user specific template is filled. + "/art:meta/art:outs/@value" The list of outs used to recommend for the + various outputs. + "/art:meta/art:parameters/@value" A list of key/value pairs to inject more + filters to the templating. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/App.java: + Change to follow the new recommendations semantics. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Added symbolic constants to distinguish "user" and "system" db connections. + +2011-08-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * doc/conf/conf.xml: + Cosmetics, let comments start with a capital and end on a full stop, + removed incorrect comment. + +2011-08-03 Felix Wolfsteller <felix.wolfsteller@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Cosmetics, let comments start with a capital and end on a full stop. + +2011-08-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java(extractOutputNames): + Fixed potential NPE. + +2011-08-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Added support for more than one db connection in datacage templating. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java: + Now you can pass a list of named db connections to the build process. + The purpose is to mix more then one database (e.g. the backend db and + the user specific one). + + To use this feature you can add an "connection" attribute + to <dc:context> with the name of the connection to use. + If no connection name is given the last used is used again. + Initially the first connection in the given list is used. + If the context is left the connection that was active before + will be active again in a stacking manner. + + When creating NamedConnection objects you can set a boolean flag + if the results coming from the connection should be cached. This + is useful e.g. for the user specific database which runs in-memory + so caching would introduce some superfluous overhead. + + * src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java: + When executing the queries explicitly pass if caching should be used. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Forgot to fetch dialect dependent SQL statement for deleting + artifacts by uuid. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Set the name of the collections at initial scan, too. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Fixed wrong SQL references. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Fixed two NPEs. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java, + src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Forwarded kill collections and artifacts events to datacage. + + * src/main/resources/datacage-sql/org-h2-driver.properties, + src/main/resources/datacage-sql/org-postgresql-driver.properties: + Added statement to delete artifact by uuid. + +2011-08-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java: + Made it compilable again. The signature of BackendListener has changed. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Completed the backend listener stuff. + + TODO I: Added some cleanup for orphaned artifacts. + TODO II: Figure out a way to delete collections/artifacts + which are delete from backend without the + backend API. + + * src/main/resources/datacage-sql/org-h2-driver.properties, + src/main/resources/datacage-sql/org-postgresql-driver.properties: + Added needed statements. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Update collection names on change. Remove artifacts from collections. + + * src/main/resources/datacage-sql/org-h2-driver.properties, + src/main/resources/datacage-sql/org-postgresql-driver.properties: + Added needed statements. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java: + Call datacage with the global context. This is needed to access the state engine. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: Changed + signatures to take the global context, too. Create artifacts via backend listener + interface. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java: + Fixed recursion bug. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java: + Added debug output. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Added backend listener for datacage. + + * src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java: + New. Proxies backend listener calls to datacage. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Implements backend listener. TODO: Update the datacage database + according the change calls. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta, + src/main/java/de/intevation/flys/artifacts/datacage/templating: + Moved/renamed package to better fit the common semantics. + DataCage.java is now call NoneUserSpecific.java to reflect the + fact that it is the template for the user independent db + analysis. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java, + src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Ajusted imports and calls. + +2011-08-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: For documentation purposes added a out-commented + section with the default configuration of the datacage. + +2011-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Delete the artifacts at before initial scan, too. They are independent + from users. Fixed problem when writing state data content. + + * src/main/resources/datacage-sql/org-h2-driver.properties: Added + statement to delete the artifacts at initial scan, too. + + * src/main/resources/datacage-sql/org-postgresql-driver.properties: + New. PostgreSQL version of the statements. The database scheme + is the same as H2. Very useful for debugging. + +2011-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Added kludge for the types of artifact data. They seem to be null + in some circumstances. Needs to be debugged! + +2011-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DBConfig.java: + Fixed default connection URL to use a namend in-mermory database. + +2011-07-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Fixed constraint. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Added some debug output. + +2011-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Removed artifact_id from facet because there + is a link via out_id -> outs.id: artifact_id -> artifacts to + find the corresponding artifact. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: Store + facets of outs into datacage db at initial scan. + +2011-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: + Store outs of artifacts into datacage db at initial scan. + TODO: store facets. + +2011-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Added 'type' column in artifacts data. + Maybe useful for filtering. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: + Store artifact data into db at initial scan. + TODO: store outs and facets. + +2011-07-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: + Add artifacts into datacage db at initial scan. + TODO: Store data, outs and facets. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Fixed spelling in sequence name. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: Simply add + collection item at initial scan if artifact was stored before. + TODO: Store new artifacts. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: Add + collections at initial scan. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: Add users + at initial scan. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Using sequences for id generation now + to make schema more compatible. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java, + src/main/resources/datacage-sql/org-h2-driver.properties: Clear database + before initial scan. + +2011-07-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/DBConnection.java: + Deleted. This stuff comes from the artifact database now. + + * src/main/java/de/intevation/flys/artifacts/datacage/DBConfig.java: + New. The db config of the datacage database. + + * src/main/resources/datacage-sql/org-h2-driver.properties: New. + The SQL statements needed for the datacage. + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + Make use of the db config. + +2011-07-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java: + New. A artifact database lifetime listener to build the initial + index of the artifacts in database. + + * doc/conf/conf.xml: Added the datacage to the list of lifetime + listeners. + +2011-07-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Added an explicit table for the outs + of an artifact. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Make the current outs of an artifact accessible only with + the global context. + +2011-07-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: Added ON DELETE CASCADE constraints. + Added state in facet. + +2011-07-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/datacage.sql: New. H2 Schema for the datacage database. + Uses special features like IDENTITY (autoincrement) typed columns. + + * src/main/java/de/intevation/flys/artifacts/datacage/DBConnection.java: + Pooled connection. + + * pom.xml: Added dependencies to H2 and Apache DBCP. + +2011-07-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/test/java/de/intevation/flys/artifacts/AppTest.java, + src/main/java/de/intevation/flys/artifacts/App.java: Removed. + This the stupid "Hello, World!" app initially created by the + maven archetype. It was never used. + +2011-07-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Argh! Usage the DOM was not thread safe (discovered with ab). + +2011-07-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/meta-data-template.xml: '$recommended' lead to XPath + errors. Using "dc:contains($parameters, 'recommended')" helps. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java, + src/main/java/de/intevation/flys/artifacts/services/meta/FunctionResolver.java: + Added some debugging. + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + Added parameters as 'parameters' to parameters. Usefull to check + for containment of variables. + +2011-07-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Added 'if log.isDebugEnabled() {}'. + +2011-07-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Made Artifact UUID optional and accept extra parameters, too. This enables + the service to be used without an arttifact and test all filters. + + <art:meta xmlns:art="http://www.intevation.de/2009/artifacts"> + <art:outs value="computed_discharge_curve,floodmap"/> + <art:parameters value="river:Elbe"/> + <art:filters value="recommended"/> + </art:meta> + + * src/main/java/de/intevation/flys/artifacts/services/meta/FunctionResolver.java: + 'contain' accept Maps and collection, too. + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + Made artifact option (= null) in recommendations. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/CompiledStatement.java: + Moved connection specific into inner class. The enables the reuse of the + compiled statement. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: The + SQL statements are now only compiled once at creation time of the builder. + Each connection now reuses them. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Added configuration for static datacage db access. + + * src/main/java/de/intevation/flys/artifacts/services/meta/App.java: Using + caches seems to need an explicit System.exit(). + + * src/main/java/de/intevation/flys/artifacts/services/meta/CompiledStatement.java: + Added support for caching the SQL statements and there results. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: Some + clean up. Reordered code for performance. Strip SQL statements more + aggressively. + + * src/main/java/de/intevation/flys/artifacts/services/meta/ResultData.java: + Made it Serializable. + + * src/main/java/de/intevation/flys/artifacts/cache/CacheFactory.java: + Introduced system property 'flys.artifacts.cache.config.file' to make + the caching configurable without pulling up the whole stack. + +2011-07-22 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Prepared the FLYSArtifactCollection to support the storage of already + loaded recommendations in its attribute document. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Adjusted to use the DataCage recommendations. The incomming document + can pass the artifacts UUID by '/art:outs/@value' the outs as a + comma separated list in '/art:outs/@value' and optional a set of + filters comma separated in '/art:filters/@value'. + + If UUID and OUTS are not given the old service is used. This + should be removed as soon as the client uses the new service. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/CompiledStatement.java: + Allow '-' in variable names. + +2011-07-21 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data-template.xml: Now, the river-id is really added to + the factory node of the wmsbackground layer. + +2011-07-21 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data-template.xml: Added the river-id to the factory node + of the riveraxis and wmsbackground layer. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java, + src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java, + src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java, + src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + Adjusted to implement changed Service interface. + +2011-07-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Refactored + the method that retrieves the Outputs for the Artifact. Now, we are able + to query the Outputs for the current state, and all outputs separately. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: The + recommendations provided by this monitor will take the Outputs of the + current state only into account. + +2011-07-21 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/meta-data-template.xml: Added conditions for each output type. + Splitted the "floodmap" output into two parts: a recommended one and a + complete one. The recommended part will only build the document tree for + the recommended artifacts; the complete part will build the whole document + tree that is available for a floodmap. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + This Hook now uses the DataCage to generate the recommended artifacts. + The output-defaults configurtion is needless now. + + * doc/conf/output-defaults.xml: Removed. The configuration of recommended + artifacts takes place in meta-data-template.xml. + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + Bugfix: the DataCage didn't start working if its builder was NOT null, + but it shouldn't start if the builder IS null. + +2011-07-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Now it is possible to directly pass a Node as a root to the builder. + The owning document if fetch by Node.getOwnerDocument(). This is + useful if you want to generate the recommendation directly into + an already existing document under a given node. + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + Changed the signature of recommend() to accept a node where to + append the recommendations. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Added a macro mechanism: + + <dc:macro name="keine-fuenf"> + <dc:text>'5' ist nicht in der Liste der Outs.</dc:text> + </dc:macro> + <dc:call-macro name="keine-fuenf"/> + <dc:call-macro name="keine-fuenf"/> + <dc:call-macro name="keine-fuenf"/> + + Macros can be defined everywhere in the template + with 'macro'. There bodies can contain all valid elements + including other 'macro's and 'call-macro's. They are + called with their 'name' with 'call-macro'. The control flow + is continued inside the body of the called macro and + will continue right after the calling 'call-macro' when + the macro body is finished. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Added a new 'if' construct similiar to XSLT: + + <dc:if test="not(dc:contains($outs, '5'))"> + <dc:text>'5' ist nicht in der Liste der Outs.</dc:text> + </dc:if> + + The control flow is continued inside the 'if' if the 'test' attribute + as an XPath expression on an empty document evalutes to true. + Else the inside is skipped. There is no 'else'. Use 'choose'/'otherwise' + if you need this. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + Added a recommend() method to generate recommendations for + a given artifact, outs and extra parameters. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added + method to extract all data at once. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/FunctionResolver.java: + New. Custom XPath function provider. Provides + 'dc:contains(Object [] haystack, Object needle)' by now. Should be + useful to check containments in 'out' lists later. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Register the FunctionResolver to the evaluated XPaths. + + * src/main/java/de/intevation/flys/artifacts/services/meta/App.java: + Added code to parse + "param:a,b,c" to "param" -> new String [] { "a", "b", "c" } to + help testing the 'dc:contains' XPath function. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added wms configurations for Saar, Mosel and Elbe. + Each river supported by FLYS requires such a WMS configuration. A WMS + should contain layers for the river axis, buildings, kilometer labels + and maybe a background layer as well. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: + Added key that is used to store a map of WMS URLs - for each river a + WMS URL. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Parse the river WMS from global configuration. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Create WMSLayerFacets with URLs based on the river and the river wms + configuration stored in the FLYSContext. + + * src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: + Adapted the initialize() signature and the method call of computeInit() + which requires a FLYSContext to retrieve the river WMS configurations. + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added the context object parameter to the computeInit() method. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Call + initialize() with the context object - which is a FLYSContext or a + CallContext. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/App.java: + Check if builder was created properly before using it. + + * src/main/java/de/intevation/flys/artifacts/services/meta/StackFrames.java: + Implements now variable provider for XPath expressions. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Added new choose/when/otherwise construct similiar to XSLT + + <dc:choose> + <dc:when test="$river = 'Mosel'"> + <dc:text>Es ist die Mosel.</dc:text> + </dc:when> + <dc:when test="$river = 'Saar'"> + <dc:text>Es ist die Saar.</dc:text> + </dc:when> + <dc:otherwise> + <dc:text>Es ist weder Mosel noch Saar.</dc:text> + </dc:otherwise> + </dc:choose> + + A 'choose' block can contain a list of 'when's and an optional + 'otherwise'. For each 'when' the test attribute is evaluated + as an XPath expression on an empty document. The result of + the evaluation is taken as a boolean value. If its value is + true the control flow is continued inside the corresponding + 'when' and the other choose elements are not tested. + If the value is values the testing continues with the next + 'when'. If no 'test' expression is evaluated to true, the + control flow continues inside the 'otherwise'. If no 'otherwise' + is given nothing happens at all. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added a config section for floodmaps. Currently, the + background layer's url and layername is defined here. + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java: + Read the background layer configuration from conf.xml. Those values are + used to create the WMSLayerFacet. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java: + The background layer facet will no longer have an extent set. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java: + Set the extent of the created WMSLayerFacets and i18n its descriptions. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added I18N strings for the + background an river axis layer. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + This facet type has a method to set the extent of a WMS layer. The + extent is written to the facets XML node in toXML() as well. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Adapted + the signature of setup() which requires a CallMeta parameter now. + + * src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: Use + the CallMeta object retrieved in setup() to call initialize(). It is now + able to i18n things. + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/App.java: New. + Standalone app to debug the datacage template. To use in a maven environment: + + -Dmeta.data.template=PATH_TO_META_DATA-TEMPLATE.XML \ + -Dmeta.data.parameters=river:Mosel \ + -Dmeta.data.output=OUTPUT.XML \ + -Dflys.backend.user=DB_USER \ + -Dflys.backend.password=DB_PASSWORD \ + -Dflys.backend.url=DB_CONNECTION_URL \ + -Dexec.mainClass=de.intevation.flys.artifacts.services.meta.App + +2011-07-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/DataCage.java: + New. First step to factor out the "Datenkorb" logic into a service independent + singleton. + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Uses the "Datenkorb" singleton now. + +2011-07-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java: + Removed "index" property, because it is already existing in parent + class. + +2011-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Improved error handling. + +2011-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/metadata/template.xml: Deleted. + + * doc/conf/meta-data-template.xml: New. Was template.xml + + * doc/conf/conf.xml: Made meta data template configurable. + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Load template from configuration not from resources. + +2011-07-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/metadata/template.xml: s/[a-z]+-id/db-id/ + Make database ids identifiable with unique name "db-id". + +2011-07-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java: + Override the toXML() method. Subclasses can now write their own XML + representation. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java: + New. This ManagedFacet uses an Element (DOM) to store the information + about a facet. The intent of this facet type is to represent a facet + stored in an Collection attribute. Different facets can have different + attributes that we need to parse, but the only thing ManagedFacets need + to do, is to adjust the attributes "active" and "position". So, those + values are set directly on the Element, the other attributes aren't + touched. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java: + New. This facet is a wrapper for another facet. This subclass of a + ManagedFacet overrides the toXML() method. The XML representation is + defined by the inner facet that is stored as member variable. The + ManagedFacet specific attributes "artifact", "facet", "pos" and "active" + are added manually. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: Uses + the toXML() method to write a facet node into the attribute document. + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: Uses + the ManagedDomFacet to save the information of a facet which is + contained in the attribute part of a Collection's DESCRIBE document. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: Uses the + ManagedFacetAdapter to save a facet, because we want to keep the + specific facet to be able to write its specific XML representation into + the Collection's DESCRIBE document. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapted the XPath of facets stored in the attribute part of the + DESCRIBE. + +2011-07-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method that returns the Outputs for the Artifact. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapeted the call of OutputParser. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: + Simplified the code to read the Outputs of Artifacts. This parser will + now longer parse the DESCRIBE documents of the Artifacts, but query the + Outputs via FLYSArtifact.getOutputs() directly. + +2011-07-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java: + Adapted the function call of ProtocolUtils.appendOutputModes(). + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + Override toXML() to add the URL and layernames to the XML representation + of this facet. + +2011-07-18 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/wmsbackground.xml, + doc/conf/artifacts/riveraxis.xml: New configurations for an Artifact + that is used as background layer in floodmaps, and an artifact that is + used as layer showing the river axis in a floodmap. + + * doc/conf/output-defaults.xml: New file to configure default artifacts + for specific output states. E.g. the floodmap state recommends a + background layer and a layer displaying the river axis. In suche case, + the floodmap state recommends two artifacts for the two layers. + + * doc/conf/conf.xml: Added new artifacts/artifact-factories and a Hook to + monitor artifacts (-> CollectionMonitor.java). + + * src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: + New. This facet is used to represent a layer in a map. So, this facet + stores information about a WMS URL and the layer names provided by this + WMS. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + facet types for the wmsbackground and riveraxis. + + * src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java, + src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java: + New. An artifact and its default state. The intent of these classes is + to generate WMSLayerFacets which represent background layers in maps. + + * src/main/java/de/intevation/flys/artifacts/states/RiverAxisState.java, + src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java: New. + An artifact and its default state. The intent of these classes is to + generate WMSLayerFacets which represent layers that display a river + axis. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added the INIT ComputeType. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + case for the INIT ComputeType while computing data. + +2011-07-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added a method computeInit() which is called to initialize data/facets + after an artifact has been created. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Repaired + broken XPath. + +2011-07-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: + Removed the code to generate new artifacts. Instead of creating new + artifacts automatically, we decided to suggest creating new artifacts + from specific types. Therefore, the DESCRIBE document of the artifacts + is extended with a node that contains recommended artifact types. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + FLYSArtifacts might be setup with the identifier of an other + FLYSArtifact. Subclasses are able to override a method called + initialize(Artifact, GlobalContext). This might be helpful to extract + required values or clone artifacts. + +2011-07-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Adapted the signature of createArtifactContext() - it returns an + instance of GlobalContext now. + +2011-07-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Debugged the water fill algorithm. Added a lot of logging. + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + Added a text field to give a water level to fill in. + +2011-07-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Moved code + to create the output modes based on the given facets to FLYSArtifact. In + addition, FLYSArtifact got a new method that returns a specific input + value as string. + + * src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java: New. + This hook monitors the "post-feed" and "post-advance". If the monitored + Artifact's state has configured recommended artifacts, this hook will + create new Artifacts. + + TODO: We have to add the UUIDs of the new Artifacts to the DESCRIBE + document of the artifact to let the client know, that there are new + recommended Artifacts. + + * src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java: New. + This Artifact is the base class for Artifacts, that represent static + data. E.g. this could be a decoration theme in a chart or a background + layer in the map. + + * src/main/java/de/intevation/flys/artifacts/states/OutputState.java: New. + This state might be used as base class for states, that doesn't require + any user input, but only provide static Facets added by a computeFeed() + operation. So, subclasses need to implement computeFeed() only. + +2011-07-13 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java: + New. Standalone Swing-App to test cross sections from database without the + hassles of our complete software stack. Runnable from a maven environment: + + $ mvn -e \ + -Dflys.backend.user=DB_USER \ + -Dflys.backend.password=DB_PASSWD \ + -Dflys.backend.url=DB_CONNECTION_URL \ + -Dexec.mainClass=de.intevation.flys.artifacts.charts.CrossSectionApp \ + exec:java + + You can set the river to be used with the system property 'river'. + Defaults to 'Mosel'. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENFacet.java: + Removed superfluous imports. + +2011-07-13 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: The FloodMapState has a new Outputmode + called "floodmap" now. + + * src/main/java/de/intevation/flys/artifacts/model/WSPLGENFacet.java: New. + This facet is used to generate WSPLGEN results. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added + the WSPLGENFacet. + + * src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java: + This state will now generate WSPLGENFacets. + +2011-07-12 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: + Fixed corner case. + +2011-07-11 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: New. + fillWater() generates a list of wet lines for a given profile and a + given water level. + +2011-07-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The + Outputs created while generating the DESCRIBE document will now have the + 'type' member set. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: Read the + 'type' member from DESCRIBE document. + +2011-07-06 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Removed a typo. + +2011-07-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: + DataFacet are now able to store the ID of the state which has created + this Facet. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Initialize DataFacets with the ID of this state. This is necessary to + renew the waterlevel data if it is no longer existing in the cache. + +2011-07-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java: A + report facet can now store the state's id and the artifact's hash value + when it has been created. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Initialize the ReportFacet and WaterlevelFacet with state id and hash + information. This has been necessary to retrieve reports and waterlevels + in states after this one - in states that we need to enter for floodmap + parameterization. + +2011-07-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java: + Changed the desired UI provider. + +2011-07-05 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added the option to continue the + waterlevel parameterization with the intent to create flood maps. + + * src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + This state is no longer a final state. The user has the option to + continue with the parameterization for flood maps based on the current + waterlevel. Therefore, this states desires the "continue" UI provider. + Clients should recognice this to just step to the next state or display + a button that lets the user step to the next state manually. + + * src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java, + src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java, + src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java, + src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java: + New. These states are used to parameterize a further calculation type: + flood map. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Required strings for the + flood maps states. + +2011-07-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix(?) for flys/issue114 + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java: + Make guessing a bit more robust. + +2011-07-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Added the math needed to calculate "W-Differenzen" in "Laengsschnitten". + Needs testing! + + * src/main/java/de/intevation/flys/artifacts/model/NamedObject.java: + Made it an interface to be usable in more than one inheritance chain. + + * src/main/java/de/intevation/flys/artifacts/model/NamedObjectImpl.java: + Implements the NamedObject interface and is the new base class of + WQ and WKmsImpl. + + * src/main/java/de/intevation/flys/artifacts/model/WKms.java: + New. Interface to associate kms with ws. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + Changed the base class to NamedObjectImpl. Renamed getKms(int) + to getKm(int) to make clear it return a single scalar value + and fullfil the WKms interface. + + * src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java: + New. Implements the WKms interface. Intended to be a lightweight + datastore for "zusaetzliche Laengsschnitte" and as results + of the WKmsOperations. + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java: + Changed base class to NamedObjectImpl. + + * src/main/java/de/intevation/flys/artifacts/math/WKmsOperation.java: + New. Operations on WKms data. + Currently only the SUBTRACTION operation is implemented. This + one is needed to calculate the "W-Differenzen". The operation + is insensitive about the km directions of the datasets. Missing + values are interpolated linear. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Adjusted to satisfy the signature change of WQKMs. + +2011-07-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/StyledXYSeries.java: New. This + XYSeries stores the style information that should be used to render this + series. These information are stored as raw XML documents. A public + method can be used to apply those style information to a + XYLineAndShapeRenderer. + + Note: The only two attributes currently supported by StyledXYSeries + items are "linesize" and "linecolor". + + * doc/conf/themes.xml: Added some more basic themes for the four + calculation methods. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: This + generator now tries to apply themes for all series contained in the + chart. If a series is no instance of StyledXYSeries, the default + renderer is used. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Removed the code that had been introduced to adapt renderers statically. + Now, each of these concrete ChartGenerators instantiates StyledXYSeries + items to put the curves into the chart. Those items contain style + information now! + +2011-07-01 Ingo Weinzierl <ingo@intevation.de> + + flys/issue135 (Diagramm: Trotz abgeschalteter Themen bleiben Beschriftungen bestehen) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: The way + to store datasets has changed. Until this revision, the concrete + generators managed their own datasets. E.g. the + DischargeLongitudinalSectionGenerator had three datasets: w, q and + corrected w. Now, there are just two datasets, managed by this base + generator - one dataset for the first Y axis and one dataset for the + second Y axis. This makes it easier to remove axes, that have no data to + be displayed. All concrete chart generators have to add their XYSeries + using two methods: addFirstAxisSeries() and addSecondAxisSeries(). + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Those concrete chart generators no longer manage datasets themself but + they use the two methods described above, to plot the data to the first + or second Y axis. + +2011-07-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Added the option to use a filter to reduce the number of items returned + by this service. + +2011-06-30 Ingo Weinzierl <ingo@intevation.de> + + flys/issue159 (WINFO: Radiobutton - Ortsauswahl bei "W für ungleichwertigen Abflusslängsschnitt" entfernen) + + * doc/conf/artifacts/winfo.xml: Changed the kilometer range input for + calculation 4. This calculation type requires a kilometer range. So, + after choosing the calculation 4, the transition model leads to a state + that just allows the input of a kilometer range with no option to + enter locations. + + * src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java: + New. A base state for the kilometer selection for calculations. The + target of this state is to provide facets for the duration curves. + + * src/main/java/de/intevation/flys/artifacts/states/DistanceSelect.java: + New. This state is used to enter a kilometer range. The difference to + the LocationDistanceSelect state is, that there is no option to enter + locations. + + * src/main/java/de/intevation/flys/artifacts/states/RangeState.java: + Improved this state to be the base state for calculation ranges. + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: This + state no longer inherits from RangeState which now is used as base + state for kilometer ranges. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added new i18n strings for + the DistanceSelect state. + +2011-06-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Downgraded Trove to 1.1-beta-5, because the new + later ones are removed from the maven repos. + + The functionality we need is in 1.1 so this downgrade should + cause no problems. + + Would be nice if we would support the maintainers of trove to + bring there new versions back into the main maven repos. + +2011-06-28 Ingo Weinzierl <ingo@intevation.de> + + * pom.xml: Repaired the JBoss repository which place has changed. + +2011-06-28 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 2.4 + +2011-06-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/WstWriter.java: + Append the corrected W column (if existing) to the WST export. + +2011-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java: + Guessing increaing w is not based on direct neighbors any more. + The second to be compared with is choosen by random of + the values before the first one. This makes the guessing + more robust against 'plateaus' of equal w values. + +2011-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ATWriter.java: Array + for constructing the spline was too large leading to non-increasing + values. + +2011-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue150 + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Invert the x axis if its guessed that water is increasing. + +2011-06-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java(guessWaterIncreasing): + Added a method to guess based on a given factor of the size (default 0.05) + if the water levels are increasing. Needed to determine in which direction + the water level curve should be orientated. Based on random to avoid + running over large dataset each time a diagram is generated. + +2011-06-27 Ingo Weinzierl <ingo@intevation.de> + + flys/issue177 (WINFO: Abflusskurven am Pegel verursachen ein Hängen des Servers) + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Commented out code to generate time ranges for series names. There + seems to be a problem while loading the discharge tables of a gauge or + while determining the start and/or end time of such discharge tables. + +2011-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/**/*.java: Removed trailing whitespace. + +2011-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Removed dead code. + +2011-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue173 + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Fixed the way the gauge was found for a given interval. + The old way does not work because it was just tested if + the station point was inside the segments which is not + necessarily true. The obvious solution to simply check + the overlapping intervals does not work either because + the gauge ranges touch each other and so more than + one gauge are returned in these cases. The River.maxOverlap() + is now used to find the gauge with the max overlapping + range. + +2011-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue147 + + * src/main/java/de/intevation/flys/artifacts/model/Calculation1.java: + Removed the 'kmUp' flag. It was an left over from former + WSP calculations (w/o ref km) leading to wrong results now. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Don't pass the kmUp flag to the calculation. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Added debug output to see the value of 'wq_free'. + +2011-06-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue86 + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + The reference gauge for calculations "am Pegel" was determined + wrong. + +2011-06-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Conversion w->q was broken. This should fix a number of issues + around "W am Pegel" calculations. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Issue an error report if a w->q conversion fails. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + The gauge to convert w->q with its discharge table was determined wrong. + +2011-06-24 Ingo Weinzierl <ingo@intevation.de> + + flys/issue174 (Diagramm: Q-Linie wird bei initialem Laden des Diagramms + anders dargestellt als bei Ansicht auf gesamten Wertebereich) + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + The chart will now have upper margins again. + +2011-06-24 Ingo Weinzierl <ingo@intevation.de> + + flys/issue172 (Diagramm: Ursprung der Diagramme bei Dauerzahlen) + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Charts of this type will have the lower X value set to "0". + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ATWriter.java: + Results are now in cm. Made it more robust against corner cases. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Removed superfluous import. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml, doc/conf/conf.xml: + Added facet config for AT exports. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added 'at' facet type. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java: + Generate AT facets. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ATExporter.java: New. + Exporter for AT facets. Needs testing. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ATWriter.java: New. + Writer for AT files. New code because our data model differs + from Desktop-FLYS. Needs testing. + +2011-06-23 Ingo Weinzierl <ingo@intevation.de> + + flys/issue157 (Diagramm: Ursprung berechnete Abflusskurve) + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Moved the method that adjusts the X-axis to include the "0" value from + ComputedDischargeCurveGenerator to DischargeCurveGenerator. Now, both + charts will include the "0" on the X-axis. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQDay.java: + Based on WQ now to make it exportable as AT. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQ.java: + New. Base class for WQKms. + + TODO 1: make it a base class for WQDay, too, + TODO 2: Generate instances of WQ instead of WQKms in "Abflusskurven" + calculations. This will save memory. + + AT exporter will get instances of this class as data model + + * src/main/java/de/intevation/flys/artifacts/model/NamedObject.java: + Add default constructor to ease inheritance. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + Based on WQ now. Removed code allready defined in base class. + +2011-06-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Add TODOs for error reports + of "Abflusskurven am Pegel". Maybe we don't need them? + + * doc/conf/conf.xml: Configure report for each calculated output type. + +2011-06-22 Ingo Weinzierl <ingo@intevation.de> + + flys/issue164 (Berechnung 4: Umgekehrtes Berechnungsintervall führt zur) + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Create the items with range information for W and Q which allows the + client to validate the user inserted values. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Arguments in filling datastructure were flip. Now + the "Abflusskurve am Pegel" looks correct again. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Removed superfluous imports. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Improved situtation on rendering "Abflusskurve am Pegel". Not + fully working, yet. + + * doc/conf/artifacts/winfo.xml: Generate facets for the location path, too. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Misspelled + the facet which prevented the facets from being to the outputs. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: + Extended to store the hash and the state id of the producing artifact/state + else it results in NPEs because the data is calculated on later (wrong) states. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Store the state id and the hash in the facet, too. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Add two + method to do calculations for a state the artifact is currently not in + and fetching the current state id. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Generate facets for "Abflusskurven am Pegel" + Not working by now. :-/ + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: New facet type + for "Abflusskurven am Pegel" + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Do calculation + in the artifact not in the output generator. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Generate the new facets. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Fetch data from facet. + +2011-06-22 Ingo Weinzierl <ingo@intevation.de> + + flys/issue161 (Diagramm: Q-Achse in W-Längsschnitten immer bei Q=0) + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + The Q axis (which is the second y axis) initially contains the 0 value. + After a zoom action has taken place, this behaviour is no longer + supported. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Draw correction curve again. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + Use correction curve to map plot to axes. Not doing so prevented + the correction curve from being drawn! + Smaller code cleanups and simplifications. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: + Added methods to directly access the components w, q and c + at a given index. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: + Attribute access via DOM instead of XPath. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Code simplification. + +2011-06-21 Ingo Weinzierl <ingo@intevation.de> + + flys/issue157 (Diagramm: Ursprung berechnete Abflusskurve) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Splitted + up zooming for x and y axes to be able to override specific axis + zoom behaviour. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + The lower bound of the x axis (which is the Q axis in such chart) is + always 0. + +2011-06-21 Ingo Weinzierl <ingo@intevation.de> + + flys/issue90 (Diagramm: Trennung derDiagrammfläche und Achsenaufheben) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Added a margin between chart data and chart axes. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue158 + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Checks for right class now. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Fix for flys/issue154 + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Checks for right class now. + +2011-06-21 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Only generate 'outs' if they have facets. + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + 'boolean ? true : false' <=> 'boolean' + +2011-06-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added the time-to-live to the DESCRIBE document. + +2011-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/artifacts/winfo.xml: Configured states to generate report facets. + +2011-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java: + Return the report. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: + Generate report facets if there are problems with the calculations. + TODO: Adjust winfo.xml to configure the facets. + +2011-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/ReportGenerator.java: + New. Generator for calculation reports. + + * doc/conf/conf.xml: Added ReportGenerator. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added type 'report'. + + * src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java: + Specialized facet for serving reports. TODO: Added them to the + calculation states. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Looped through CallMeta for i18n purposes. TODO: do i18n + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed superfluous import. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Added some override annotations. + +2011-06-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/CalculationResult.java: + New. Used to transport the data and the error report. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation1.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation2.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation3.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java, + src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + Use the CalculationResult now. + +2011-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation1.java: + Allow an explicit reference km to enable calculation "am Pegel". + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + If a calculation "am Pegel" is done, take start km of the + calculation range and find the gauge in which range it is located. + Take the station of the gauge as the reference km. If no gauge + is found the calcualtion falls back to calculation "auf freier Strecke". + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Replaced another inefficient attribute extraction via XPath + with direct DOM access. + +2011-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Removed dead code. + +2011-06-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java + src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java, + src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java, + src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Only generate facets when needed. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: + Removed more XPath for simply accessing attributes of an element. + + * doc/conf/cache.xml: 200 elements in memory for "computed.values" are enough, + LRU as eviction strategy is sufficent. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Use + more 'standard' Java naming conventions. + +2011-06-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Merged in the facet-slt branch to bring in the 'facet' feature. + + * doc/conf/artifacts/winfo.xml: Fixed some facets. + + * doc/conf/cache.xml: Added a "computed.values" cache to store the + results of the WINFO calculations. + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java: + Add support for index per facet to make them unique and identifiable. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + New. Inteface to be used to access the facet names of the configuration. + + * src/main/java/de/intevation/flys/artifacts/model/DataFacet.java: New. + A facet to be used to have raw access to the computed data of an artifact. + Useful to export things like CSV and WST. + + * src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: New. + Specialized facet to access the water level data stored in WQKms arrays. + + * src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java: New. + Specialized facet to access the duration data stored in WQDay data structures. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Facets are + now generated dynamically from the current available ones stored with + the artifact. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: Added + methods computeAdvance() and computeFeed() called if artifact is fed or + adance. This overwritten in subclasses to do the state depending calculations. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java: These + states overwrites the computeAdvance() and computeFeed() methods to do + the corresponding WINFO calculations. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Calls + computeAdvance() and computeFeed() if artifact is fed or advanced. Centralized + the caching mechanism. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java, + src/main/java/de/intevation/flys/collections/AttributeParser.java, + src/main/java/de/intevation/flys/collections/OutputParser.java, + src/main/java/de/intevation/flys/collections/AttributeWriter.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adjusted the code to cope with the indices of the facets. Used + DOM to access the attributes instead of XPath. Removed smaller bugs + concerning position generation. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/OutGenerator.java: + Forwarded facet references. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Uses facets to fetch data and generate output now. + +2011-06-17 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added a new parameter "wq_free" that + determines the mode of calculation 1. If it is "false" (default), + the calculation should be bound to a gauge. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method to retrieve the information about the "wq_free" parameter. + +2011-06-17 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added a facet for corrected W in + computation 4. + +2011-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Got rid of namespace in result document. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + flys/issue77 (Diagramm: Beschriftung der Kurven bei Dauerlinien) + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Give the curves in the chart names. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added titles for duration + chart curves. + +2011-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Write top 'Oberkante' and bottom 'Unterkante' to out going XML + if they exist. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Write the min/max W/Q ranges as art:range elements into the DESCRIBE. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + This state that is used to retrieve locations will now write the + kilometer range of the selected river into the DESCRIBE document. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation1.java: + New. Factored out version of "Wasserspiegellage" calculation. + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + + Removed some dead code. + + * src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: + Added Override annotation and used quick access method. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Looped through error reporting use by interpolate. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Used factored out version of calculation 1. Removed dead code. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation2.java: + New. Factored out version of "Abflusskurve". + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Loop errors through w/q at km interpolation. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use factored out version of calculation 2. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation3.java: + New. Factored out version of "Dauerzahlen". + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Loop errors through for q->w interpolations. + + * src/main/java/de/intevation/flys/artifacts/model/WQDay.java: + Added constructor to directly create with calculated results. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Added method to return the number of problems. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use factored out version of calculation 3. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQCKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQDay.java: + Added methods to remove NaN values. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + New. Base class for calculations. Used to collect problems occuring + during calculation. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Extends Calculation now. Looped through the problem reports to + base class. + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Looped through the problem reports. + +2011-06-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Append the min/max range and a transformation matrix for each axis. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Instantiate the InfoGeneratorHelper with a XYChartGenerator instance. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Changed the zoom operation. The zoom values defined in the chart request + document are no longer absolute values for a specific axis. Those values + represent percental values for the start and end point of x and y axes. + E.g. a chart has three axes with the following ranges: + - x axis : 0 - 10 + - y axis 1: 20 - 40 + - y axis 2: 40 - 90 + - zoom values for x: 0.1 - 0.9 (10% - 90%) + - zoom values for y: 0.2 - 0.8 (20% - 80%) + The produced chart will have the following ranges: + - x axis : 1 - 9 + - y axis 1: 24 - 36 + y axis 2: 50 - 80 + +2011-06-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Map datasets to axes correctly. + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Determine the gauges by their station positions. This hopfully + fixes the problem with wrong assigned gauges and invalid segments. + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Added more debug output. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + flys/issue103 PART 1 (WINFO: Wasserspiegellagenberechnung / Layout-Inkonsistenz) + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Selected values are formatted with the current locale. The static part + of the DESCRIBE document will now contain i18n formatted numbers. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + flys/issue93 (WINFO: Benennung der Berechnungsart korrigieren) + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: Changed the name of + calculation 4. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Made the range determination more robust against NaN values. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + The second y axis is set to position "1". It was set to "2" before, but + in that case, there was no position "1". + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + s@m³/s@m\\u00b3/s@ + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Only generate an axis element if a axis really exists. + +2011-06-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Simpified array swapping. + +2011-06-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Use java.util.List instead of java.util.Vector + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Removed superfluous imports. + +2011-06-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + createItem() is not abstract any longer to avoid code repetitionin sub classes. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Removed duplicated code, inserted default constructors and Override annotations. + +2011-06-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Append axes range information to the info document. + +2011-06-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + If feed() fails do not store invalid values in database. + +2011-06-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Removed asymmetrical "- 1" from width calculation. + +2011-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Fixed problem when more than one value per segment are given. + +2011-06-05 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Refactored version of "Berechnung 4" + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java: + Added instance fields for a reference point (= location of gauge) + and backup of values (needed for naming). + + * src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: + Added a constructor to be created from a WQKms. This is helpful + if a WQKms is replaced by a back jump correction. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + New. Outfactored version of "W bei ungleichmaessigen Abflusslaengsschnitt". + Much cleaner now and it should have a better handling of the corner + cases. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Removed the linear interpolation stuff. It is now in Linear. Removed + the LinearRemap interpolation method because it is not needed any + longer. Added a method to interpolate a given km with a given + function. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed the old calc 4 and used the new one. + + * src/main/java/de/intevation/flys/artifacts/math/LinearRemap.java: + Deleted. Not needed any longer. + + * src/main/java/de/intevation/flys/artifacts/math/Function.java: + New. Interface for a uni-variate real function. + + * src/main/java/de/intevation/flys/artifacts/math/Identity.java: + New. Implements Function with f(x) = x + + * src/main/java/de/intevation/flys/artifacts/math/Linear.java: + New. Implements Function with f(x) = m*x + b + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Factored some stuff out to DoubleUtil. Removed some dead code. + Does some rounding correct. + + * src/main/java/de/intevation/flys/utils/DoubleUtil.java: New. + Centralized utils surrounding common double operations. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Removed superfluous imports. + +2011-06-03 Ingo Weinzierl <ingo@intevation.de> + + flys/issue90(Diagramm: Trennung der Diagrammfläche und Achsen aufheben) + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Determine the ranges of x and y axes. If no zoom ranges are given, we + will determine the min and max xy values in the dataset manually, + because JFreeCharts adds a margin to the left and right of the data + area automatically.. + +2011-06-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Moved + the chart creation into an own public method. This lets the + ChartInfoGenerator create charts without duplicating code. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Limited the possible class for generators to XYChartGenerator. This + enables the ChartInfoGenerator class to do the whole chart creation + stuff itself without outsourcing the code to concrete subclasses. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveInfoGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveInfoGenerator.java: + Removed the code to generate charts - this is done in ChartInfoGenerator + now. + +2011-06-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Added new + methods to extract the x and y ranges from request document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added a + method that zooms the chart to the specified x and y ranges. + +2011-06-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Set collection ttl to 6 hours. + +2011-06-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java: + New. Parse segments only once. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Expose new parser to artifacts. TODO: Use it. + +2011-06-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Changed interpolation methods to interpolate to an arbitrary position + in a given double result array as a preparation for segment independent + calculation. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed superfluous import. + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Fixed cause for crashing: Run back too far in some siutations. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Refactored range code a bit. Needs more work. + +2011-06-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Interchange the lower and upper x value of the chart if the x-axis is + inverted before the matrix values are computed. Now, the matrix is able + to work with charts that have an inverted x-axis. + +2011-06-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: New. A + chart info generator generates a document that contains meta information + for a specific chart. Concrete instances of this abstract class need to + instantiate concrete ChartGenerators and dispatch nearly all methods of + an OutGenerator (init(), doOut(), setMaster()) to this instance. The + generate() method is implemented in the ChartInfoGenerator itself. It + creates a chart with help of the ChartGenerator instance and builds a + document that contains meta information of this chart. + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: New. + This helper is used to create the chart info document. At the moment, + the only information that is included in this document is a + transformation matrix to transform image coordinates into chart + coordinates. + + NOTE: The transformation matrix creation needs some work to support + charts with inverted X axis. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveInfoGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveInfoGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveInfoGenerator.java: + Concrete instances of ChartInfoGenerator that create the chart info for + the currently supported chart types. + + * doc/conf/conf.xml: Registered new OutGenerators. + +2011-05-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added support for the 'type' paramter of the collection's out() + operation. + +2011-05-31 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Use an explicit reference km for interpolation now. + +2011-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/cache.xml: Introduced cache to store the distance info per river. + This boosts performance in following ab setup from 3.61 to 39.91 requests/secs. + + $ ab -c 20 -n 1000 -p distances.xml http://127.0.0.1:8181/service/distanceinfo + + $ cat distances.xml + <?xml version="1.0" encoding="UTF-8"?> + <art:river xmlns:art="http://www.intevation.de/2009/artifacts">Elbe</art:river> + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: Added + an iterator result to avoid construction expensive interim lists. + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: Use + the cache if configured. + +2011-05-30 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue82 + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Only successful interpolations are named. + +2011-05-27 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Make it work independent of river flow direction. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Fixed bug in ordering segments + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Re-enabled + calculation of the back jump correction. Fixed more flow direction issues. + +2011-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed call of XMLDebug class which is not in the version control. + +2011-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Moved the code part that skips themes right after the part that sets the + master artifact for the OutGenerator. We need this master artifact to + display empty charts - master artifact is used to create titles and + axes. + +2011-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Deactivated themes are not put into the chart. + +2011-05-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: + Repaired broken XPath expressions to find the output modes in an + attribute document of a collection. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: This + writer will now create a document that has a root node art:attribute. + Before these changes, the document's root node was art:outputs which is + part of the attribute document but not the right root node. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapted some XPath expressions and corrected the the process to create + attribute documents. + +2011-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/LinearRemap.java: + Made it work independent of from/to order. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Added method to extract the ranges correctly from data. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use the correct ranges. Comment out backjump detection temporarily. + +2011-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Generate fields for w/q input depend on flow direction. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Moved km up question out of loop. +2011-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Take the flow direction into account. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Prevent NPE. + + * src/main/java/de/intevation/flys/artifacts/states/RangeState.java: + Allow to be 'from' greater than 'to' in ranges. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Negate + step if 'from' is greater than 'to'. + +2011-05-26 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Round exploded values to a precision of 1e-6. + +2011-05-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Qs are now stored in ranges for each column. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory2.java: + Deleted. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Was WstValueTableFactory2. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: Fixed + node linking bug. Removed dead code. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Q values are now stored in range trees by each column. The qs of the rows + are removed and the calculations are adjusted. Removed dead code. + +2011-05-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Moved cache name to WstValueTableCacheKey. Do not cache null references. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableCacheKey.java: + Moved cache name into this class. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Store QRangeTree for each column of value table. TODO: Use them! + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory2.java: + Intended as a replacement for WstValueTableFactory, but is work in progress. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: Fixed + index errors and added methods to dump as graphviz graph. + +2011-05-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Improved the validation of WQ values. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Use the + correct input data object to determine the selected WQ mode (range or + single input). + +2011-05-24 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-40 (part I/II) + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Write default values (values already selected by the user before) of the + input data items into DESCRIBE. + +2011-05-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Removed needless imports. + +2011-05-24 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-85 (part III/III) + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Added a static function that returns the kilometer values (double[]) + from locations input (whitespace separated double values). + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Adapted + the getKms() method. It will now return a computed array of kilometers + if we had inserted a range, or it will return the inserted kilometers if + we had inserted locations. + +2011-05-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Moved cache key to separate class. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableCacheKey.java: + New. The new cache key class. + +2011-05-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: + Model to store the q values of a WST column efficiently. First + building block not to store the q values directly aside the + w values. + +2011-05-24 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-85 (part I/III) + + * doc/conf/artifacts/winfo.xml: Added two further field 'ld_mode' and + 'ld_locations' to the range/locations state to track the selected mode + and locations. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Added methods to validate the user inserted locations. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method to determine of a range or locations have been inserted. + +2011-05-23 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-62 (part II/II) + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Dump the + artifacts state/data in DEBUG mode in describe(). + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java, + src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + States will no longer store data. The only reason for states storing + StateData is to know about the necessary data for this state. If a State + needs to access the user input for a specific StateData object, it needs + to query the FLYSArtifact which stores the data. + +2011-05-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method to dump the artifacts state(s)/data. + +2011-05-23 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue84 + + * src/main/java/de/intevation/flys/artifacts/model/WstFactory.java: + Forget to select wst kind. + +2011-05-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + flys/issue81 + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + weights for kms were swapped. + +2011-05-20 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 2.3.1 + +2011-05-20 Ingo Weinzierl <ingo@intevation.de> + + * Changes: Prepared changes for the upcoming release. + +2011-05-20 Hans Plum <hans@intevation.de> + + * NEWS: + Hint to Release 2.3.1. For further information look into module + flys-client/NEWS + +2011-05-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java (getExplodedValues): + Increment kms array size by one to take the end of range, too. + +2011-05-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Sort by rows (should not be necessary). + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Use unsharp km lookup (epsilon = 0.0001). This fixes the problem + that some kms were not found. + +2011-05-19 Ingo Weinzierl <ingo@intevation.de> + + flys/issue66 + + * src/main/resources/messages_en.properties: Fixed broken template. + +2011-05-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Set the name of the computed discharge curve objects. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + The curves of this chart will now have names that consist of the word + 'Discharge Curve', the river name and the kilometer that has been used + for the computation. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for the + computed discharge curves. + +2011-05-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Added convenience method isQ() to determine if we are + doing Q calculations. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Reintroduced titles for the "W for unausgeglichene Abfluesse". + +2011-05-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + The curves will now have names that consist of the gauge name and its + valid time range. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for the + discharge curves. + +2011-05-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Removed dead code. + +2011-05-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use the correct method to generate kms. + + * src/main/java/de/intevation/flys/artifacts/math/LinearRemap.java: + Added some logging to test the map in debug mode. + +2011-05-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Made getExplodedValues static. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use new logic to calculate "W fuer ungleichwertige Abfluesse". + Not working, yet. + + * ChangeLog: Fixed former entry. + +2011-05-18 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Registered the WST export for discharge + longitudinal sections. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Set the + names of the discharge longitudinal section computation results. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + The W/Q curves in the chart will now have names. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + The WstWriter is filled with column names in an own method. So, we are + able to override this process in subclasses. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + Adapted the column names for the WST export. + +2011-05-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + Work on flys/issue69 + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use new logic to calculate "Wasserstand/Wasserspiegellage". + Compared to desktop FLYS are the results are structurally right + but a bit off in the positions after the decimal points. + Maybe a result of the interpolation? Need to debug this. + +2011-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + W and Q curves will now have names based on the defined W or Q values + for the waterlevel computation. + +2011-05-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/NamedObject.java: + New. This object is used to give objects a name. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: Inherit + from NamedObject now. Because we need to display names for those objects + in different places. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The WQKms + objects returned by a waterlevel computation will now have names. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Insert the column names for the WSTs into the WstWriter. + + * src/main/java/de/intevation/flys/exports/WstWriter.java: The column + names are written into the head of the WSTs now. + +2011-05-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstLine.java: New. This + class is used to store the W/Q values of a specific kilometer of a WST. + + * src/main/java/de/intevation/flys/exports/WstWriter.java: New. A writer + that creates WSTs. + + TODO: The header of the WSTs is not finished. The Q descriptions are + missing. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: + Enabled WST exports. + + * doc/conf/artifacts/winfo.xml: Registered the WST export for waterlevels. + +2011-05-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/utils/Formatter.java: New. This class + supports functions to retrieve formatters for specific types of data + used in FLYS. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Removed the formatter declaration - the whole formatter stuff is done in + Formatter now. + +2011-05-17 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-72 + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java: + Repaired broken XPath expressions to extract start and end kilometer. + +2011-05-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Removed the Hibernate loading stuff. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + New. The Hibernate loading. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use the WstValueTableFactory for loading now. + +2011-05-17 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 0.1 aka Version 2.3.0 + +2011-05-16 Hans Plum <hans@intevation.de> + + * NEWS: + New. Giving some user specific perspective to new functionality and + changes. This file references releases dates only; details can be find + in the client module at flys-client. + +2011-05-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + First step to calculate "W fuer ungleichwertige Abfluesse" correctly. + flys/issue55 + + * src/main/java/de/intevation/flys/artifacts/math/LinearRemap.java: + New. Remaps "gleichwertige" Q values to the corresponding + "ungleichwertige" Q values depending on km. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Remap the Q values "ungleichwertig" depending on the + "gleichwertige" ones. + +2011-05-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + First step to fix flys/issue69 + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + New code path to implement the calculation of "Wasserstand/Wasspiegellage" + correctly. TODO 1: Use new path in UI. TODO 2: Remove unused old code. + +2011-05-13 Ingo Weinzierl <ingo@intevation.de> + + * Changes: Prepared Changes for the upcoming release 2.3 - see Changes + file to get to know about the changes of the version numbers. + +2011-05-13 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-37 + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: This + state would be happy if there is a UI provider called "river_panel". + +2011-05-11 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Added new + methods that return the requested chart size as integer array [width, + height]. The requested size is read from the incomding request document. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: The size + of a chart is no longer static. The requested size is fetched using + ChartGenerator.getSize(). + +2011-05-11 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-52 + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + The X-Axis of such a chart is inverted, if the head of the river is not + at kilometer 0. This type of charts always have the head of the river at + the left side. + +2011-05-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Make incoming XML symmetric to DistanceInfoService. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-47 + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Adjusted temporarily the color of the W, Q and corrected W curves to + distinguish each other. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Adjusted the plot of xy charts - the gridlines are displayed now. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + ISSUE-53 + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Added a method that returns the preferred locale based on the available + locales of the server and the desired locales of the request (CallMeta). + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: Added a + method that creates a number formatter with minimum and maximum digits. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Formatted the number values of the CSV exports. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java: + New. A data structure that enables us to save a data triple: a range + that consist of lower and upper double value and a set of values that + belong to this range. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Implemented the validation of W/Q values. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: New + method to retrieve i18n messages based on keys. + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java, + src/main/java/de/intevation/flys/exports/WaterlevelExporter.java, + src/main/java/de/intevation/flys/exports/DurationCurveExporter.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Added headers for CSV exports. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added new i18n strings for + CSV headers. + +2011-05-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Fetches river name from incoming XML document. If no river is given all + infos about all rivers are listed. + + * src/main/resources/metadata/template.xml: Templates honors the 'river' + parameter. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Extended to pass parameters to the templating. Added support for + type conversion. + + * src/main/java/de/intevation/flys/artifacts/services/meta/StackFrames.java: + Take parameters as an initial stack frame. + + * src/main/java/de/intevation/flys/artifacts/services/meta/TypeConverter.java: + New. Converts types off stacked variables. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added a + method to add subtitles to charts. The implementation in this class does + not add any subtitle. Concrete subclasses may override this method to + add some. + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Add subtitles to charts. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n templates for + compound messages (chart subtitles). + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + Added new methods to retrieve translated compound messages. + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: Added a + method to set the master artifact that should be used for some special + operations. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/AbstractExporter.java: + Implement the setMasterArtifact() method of the interface. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Call OutGenerator.setMasterArtifact(). + + NOTE: The determination of the master artifact needs to be implemented! + +2011-05-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Removed + hard coded dev code that defined a WQ mode. + +2011-05-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + Stripped ugly extra whitespace from output introduced by + templating. + +2011-05-09 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/metadata/template.xml: Added forgotten + columns of fixation WSTs. + +2011-05-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: Added a + method to retrieve i18n strings. + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Enabled i18n support for chart title and axes labels. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for the + chart types above. + +2011-05-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java: + New. This OutGenerator exports the data of a discharge longitudinal + section computation. + + * doc/conf/conf.xml: Added the DischargeLongitudinalSectionExporter. + + * doc/conf/artifacts/winfo.xml: Added the exporter with CSV facet to the + discharge_longitudinal_section state. + +2011-05-07 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Added code to make back jump correction work with both + potential flow directions. + +2011-05-06 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/resources/metadata/template.xml: + Added data cage configuration for 'Längsschnitt'. + +2011-05-06 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added the missing Q facet for discharge + longitudinal sections. + + * src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: New. A + derived dataset to store W/Q values with corrected Ws for a kilometer + range. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: Some new + methods and a new constructor to initialize this data object with a + predefined set of values. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: New + methods to retrieve the W/Q values for the 'discharge longitudinal + section' computation. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: New + methods to retrieve and compute data used for the 'discharge + longitudinal section' computation. + +2011-05-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Bugfix: just write the ranges of gauges into the DESCRIBE if the + 'wq_values' data item is required. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n messages used in + the DESCRIBE of the WQAdapted state. + +2011-05-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Changed the title of the y-axis (now 'W [NN+m]'). + +2011-05-05 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Improved the transition model to reach the + output state for creating 'discharge longitudinal section' charts. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a + method that returns all gauges of the selected river based on a the + given kilometer range. + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: New. + This state creates a set of elements for the DESCRIBE that consist of a + tuple of kilometer values. The number of elements depend on the number + of gauges intersected by the given kilometer range. + + * src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java: + New. This state is the output state that is reached after the 'discharge + longitudinal section' computation has been chosen. + +2011-05-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Default + step width between two kilometers added - if no step width is given, + this default width is used. + +2011-05-05 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Fixed a potential NullPointerException if there is just a single + kilometer given to create a longitudinal section. + +2011-05-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Added http://repository.jboss.org/maven2 repo + to fix flys/issue30 + +2011-05-04 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + To make diagram generation possible ws are now generated from qs + because they are many ws having different qs. + +2011-05-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + Fetch the WQ data from WINFO artifact and write those values into the + CSV export. + +2011-05-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added + methods to compute and retrieve the data for discharge curves (computed). + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + Fetch the computed discharge curve data from WINFOArtifact and add the + values into the JFreeChart dataset. + +2011-05-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added new transitions and states to enable + the WINFO artifact for computing discharge curves. + + * doc/conf/conf.xml: Added OutGenerators that generate computed discharge + curves and exports for its data. + + * src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java: + New. This state is reached if the user chose the computed discharge + curve. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java: + New. This is only a stub implementation at the moment. This + OutGenerator should create computed discharge curves later. It extends + the DischargeCurveGenerator which should do the same stuff for discharge + curves for gauges. + + * src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java: + New. This is only a stub implementation at the moment. This OutGenerator + should create the exports of the discharge curve computation. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added a new output mode for the duration + curve state (CSV export). + + * doc/conf/conf.xml: Added a new OutGenerator to export duration curve + computations. + + * src/main/java/de/intevation/flys/exports/AbstractExporter.java: New. + This abstract OutGenerator represents the base class for exporting + computed data. Currently, the CSV export is supported. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Moved + the most code to export to CSV into the AbstractExporter. + + * src/main/java/de/intevation/flys/exports/DurationCurveExporter.java: + New. This exporter exports the computed data of a duration computation. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Modified a wrong debug statement which would confuse the user. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added a new output mode for the waterlevel + state (CSV export). + + * doc/conf/conf.xml: Added a new OutGenerator to export waterlevels. + + * src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: New. + This OutGenerator exports the data of a waterlevel computation. Note: + It is necessary to specify the desired facet (e.g. + 'waterlevel_export.csv'). + + * pom.xml: Added a dependency to OpenCSV. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Introduced an "export" output target. If the target is "export", a + facet (read from the incoming xml document) is a necessary parameter + that determines which facets are written to the output. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages_en.properties: Bugfix: replaced german + string (copy & paste mistake). + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added new i18n strings for + for the location selection. + +2011-05-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + New. An OutGenerator for creating duration curves. + + * src/main/java/de/intevation/flys/artifacts/model/WQDay.java: New. A + model class to store necessary data for creating W and Q facets of a + duration curve. This model stores W, Q and Days. + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java: + Added a function to retrieve tuples of (day, q) based on a given gauge - + these tuples are necessary for creating duration curves. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added + methods to compute and retrieve the data necessary for creating duration + curves. + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + Bugfix: improved the access to the location array (avoid + NullPointerException). + + * doc/conf/conf.xml: Registered the new OutGenerator for duration curves. + +2011-05-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/visualize-transitions.xsl: State quoting was done wrong. + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Enhanced the transition model to reach the + final state for creating duration curves. + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + New. This state should be reached to just insert an array of locations. + + * src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java: + New. This state is reached if the duration curve calculation is + selected. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Adjusted + getDistance() so that it takes care on inserted locations - not just + inserted ranges. + +2011-05-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/cache/CacheFactory.java: + Flush/persist caches at program exists. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Commented out too eloquent debug output. + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Uses the methods of FLYSArtifact to retrieve the necessary information + rivername and selected distance. + +2011-05-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Added interpolateW method to take reference to result ws array + as an argument to avoid expensive array allocations in km iterating + loops. + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + Added a constructor to create backing trove datastructure + with the right capacity. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Move allocation of result ws out of km loop. + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added two further data items in the WQ + selection state. Those items are necessary to store the information + about the selected mode (range/single selection) and the values of the + single selection. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: If + there is no value for a data item, this item is not written into the + static DESCRIBE part. + + * src/main/java/de/intevation/flys/artifacts/states/RangeState.java, + src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Renamed the method to validate upper and lower values. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: This + state can now handle values inserted in the single selection. Therefore, + new validate methods has been added. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: The + methods getWs() and getWs() take care on the values inserted in the + single insert mode of the client which enables the user to insert single + W and Q. + +2011-05-02 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Repaired getQForW() by calculating indices on right dimension. + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: New + methods for retrieving selected W values (getWs()). + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The + method for retrieving waterlevel data takes care on selected Ws, now. + The selected Ws are transformed using the DischargeTables.getQForW() + into Q values. + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Removed an unused parameter 'result' of getQForW(). + +2011-05-02 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Removed + the getDataset() method and replaced it with a addDataset() method. + On this way, concrete subclasses of this OutGenerator can have multiple + datasets (e.g. different datasets for W and Q). This abstract method is + called after the chart generation is finished. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Both classes implement the addDataset() method. The + LongitudinalSectionGenerator has already multiple datasets for W and Q. + Both are added to the chart - both have an own range axis. + +2011-05-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Use the cache for the wst value table if configured. + + * doc/conf/cache.xml: Choose a more precise name for the + wst value table cache. + +2011-04-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Added dependency to Ehcache. Apache 2.0 license. + + * doc/conf/conf.xml: Added configuration of ehcache. + + * doc/conf/cache.xml: New. Cache configurations. + + * src/main/java/de/intevation/flys/artifacts/cache/CacheFactory.java: + New. Factory to access caches. + +2011-04-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Forgot to add. + + * src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java: + New. Given a database connection and a XML template it generates + an output with meta data about the database. + + * src/main/java/de/intevation/flys/artifacts/services/meta/CompiledStatement.java: + New. Holds prepared statements optimized to be run in the stack of + contextes. + + * src/main/java/de/intevation/flys/artifacts/services/meta/StackFrames.java: + New. Model to hold a hierarchical scope of variables. + + * src/main/java/de/intevation/flys/artifacts/services/meta/ResultData.java: + New. Stores data set fetched from a sql select to be iterated in + a context. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java, + src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed superfluous imports. + +2011-04-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Added meta data service. + + * src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java: + Stub for the meta data service. + + * src/main/resources/metadata/template.xml: Initial template for + the meta data service. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Bugfix: Now, curves for Q values are drawn into a longitudinal section + chart as well. Therefore, it was necessary to change the datastructure + of the inner class ThemeList that stores all themes included in a chart + in an ordered list (stored in a java.util.Vector now). + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: New. An + abstract base class for ChartGenerators that create XY charts. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Sourced the generate() method out to the XYChartGenerator. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Implemented the methods to add W and Q facets to the chart. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Improved + the calculation of the step with for ranges. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: Added a + method that returns the number of elements stored in the data pool. + +2011-04-29 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + Added a get() method which takes destination array as an + argument. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: Changed the + data structure to store w, q and kms values from List<Double> to + TDoubleArrayList which stores native double values instead of big + Double values. + + * pom.xml: Added the GNU Trove dependency. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: Added the + name a the requested facet to doOut(). Concrete generators should just + create output for this facet now. + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java, + src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + Adapted the method signature of doOut(). + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapted the method call of OutGenerator.doOut(). + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: Added mappings for the facets + longitudinal.section.w and longitudinal.section.q. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added some + methods to retrieve necessary information for computing the data of a + waterlevel. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added + methods to compute and retrieve the data of a waterlevel computation. + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: New. This + model class represents a pool of data triples that consist of W, Q and + Kms information. This class might be used to compute data for creating + longitudinal section curves (which are based on those W, Q and Kms + values). + +2011-04-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Bugfix: Removed endless loop and a bug while iterating over Hibernate + results. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + New. An OutGenerator that creates longitudinal section curves. + + NOTE: This is just the stub - the out creation needs to be implemented! + + * doc/conf/conf.xml: Added the LongitudinalSectionGenerator. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Bugfix: Added missing <output-generators> section. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WaterlevelState.java: New. + This state should be reached if the 'calc.surface.curve' calculation + method has been chosen. + + * doc/conf/artifacts/winfo.xml: Modified a transition and added the + WaterlevelState. This state is reached if the 'calc.surface.curve' + calculation method has been chosen. It currently has 1 output - a + longitudinal section that is not implemented yet! + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/transitions/ValueCompareTransition.java: + New. This transition is valid if the a data object of the current + artifact equals/notequals a configured value in the transition model. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Bugfixes: + - Adapted the parameters of the isStateReachable() call - added the + artifact and the current state. + - Append the outputs of a current state if the state is filled with + valid data. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java: + Added the missing init() method that has been introduced in the + interface some commits ealier. + + * src/main/java/de/intevation/flys/artifacts/transitions/TransitionFactory.java: + Call init() after a Transition has been created. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: + Bugfix: Introduced a <art:outputs> node in the attribute document of a + Collection that contains further <art:output> nodes - instead of having + multiple <art:output> nodes at toplevel of the document. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Adapted the XPath to retrieve the outputs in the attribute document of a + Collection. + +2011-04-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * contrib/visualize-transitions.xsl: Added to create a + Graphviz digraph out of the config.xml. Usage: + + $ xsltproc --stringparam base-dir ../doc/conf/ \ + contrib/visualize-transitions.xsl \ + doc/conf/conf.xml > transitions.dot + + $ dot -Tsvg -o transitions.svg transitions.dot + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + If no data has been inserted so far, an IllegalArgumentException is + thrown. + +2011-04-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:: + A lot of new methods to retrieve the theme of a facet - used while + creating the output of a facet/artifact. If a facet has no theme yet, it + is initialized. + +2011-04-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/AttributeParser.java, + src/main/java/de/intevation/flys/collections/OutputParser.java: Removed + useless imports. + +2011-04-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartGenerator.java: New. An + abstract OutGenerator that might be used to create chart output. Some + basic things that are equal in all charts should be done here! + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + This OutGenerator no longer implements the OutGenerator directly, but it + extends the ChartGenerator now. + +2011-04-27 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Restructured the out() operation of a collection: Now, we collect a list + of artifacts/facets and use this for the OutGenerator. Its doOut() + method gets the attribute of an artifact - the position and the active + state is managed by the Collection itself. + +2011-04-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java: New. + a specialized facet that stores information about its position and its + state (active/inactive) in an output of a collection. + + * src/main/java/de/intevation/flys/collections/AttributeParser.java: New. + This parser takes the attributes (XML) of a collection and extracts the + contained outputs with its facets. The result is a Map<String, Output>. + + * src/main/java/de/intevation/flys/collections/OutputParser.java: New. + This parser is used to query the artifact's DESCRIBE and to extract the + supported outputs. The result is a Map<String, Output>. + + * src/main/java/de/intevation/flys/collections/AttributeWriter.java: New. + This writer merges the outputs contained in an attribute of a collection + with the outputs of a collection's artifacts. + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + The attributes of a collection are written into its DESCRIBE document + now. The OutputParser and AttributeParser are used to read the supported + attributes by the collection and its artifacts - the AttributeWriter is + used to merge both attributes and create a final attribute document. + +2011-04-26 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java, + src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + The facet-2-theme mappings are initialized at startup and stored in the + FLYSContext. + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: Added a + function that retrieves a theme from FLYSContext based on its name. + +2011-04-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Corrected a silly c&p mistake. + +2011-04-22 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + + Implementation of the "Ruecksprungkorrektur" to be done in + "W fuer angepassten Abflusslaengschnitt". + + All tests show the expected results. In some corner cases the + algorithm described in the "Anwenderhandbuch" chapter 3.3.4.3 "Korrektur" + has some definition shortcomings: + + a - What should happend when you cannot find point 2 because + you cannot step back one quarter from point 3 because there + is no data there any more (river too short in this direction)? + The implemented algorithm raises point 3' only to an + according factor. E.g. If you can step back the whole quarter + distance the elevation is the full quarter. If you can + step back only the half of the quarter the elevation is + only an eighth. + + b - If the water heights between point 2 and 3 are constant then + the algorithm will produce a spline interpolation that + lowers those values. Is this intended? + + For real data the back jumps are expected to be more in the middle + of the distance ranges so the corner cases are maybe not so + important. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + Removed superfluous import. + +2011-04-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: Removed debug + code that has been commited by accident. + +2011-04-21 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/themes.xml: New. A first small theme configuration. + + * doc/conf/conf.xml: Added a link to the theme configuration. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: + Defined a key that is used to store a themes map in the FLYSContext. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + The theme configuration is read at startup and the themes are stores in + the FLYSContext. + +2011-04-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/themes/Theme.java, + src/main/java/de/intevation/flys/themes/DefaultTheme.java: + New. The interface and its default implementation that represents themes + used to style charts and maps. + + * src/main/java/de/intevation/flys/themes/ThemeField.java, + src/main/java/de/intevation/flys/themes/DefaultThemeField.java: + New. The interface and its default implementation that represents fields + in themes. A theme might be "Lines" and one of its field might be + "Color" or "Size". + + * src/main/java/de/intevation/flys/themes/ThemeFactory.java: A factory + that creates new themes based on a theme configuration. + +2011-04-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Implementation of "Abflusskurve/Abflusstafel" calculation. + + Added method interpolateWQ() which takes an km and results in a + tuple of two double arrays containing the w/q values interpolated + between the surrounding w/q values of the table. + w values are interpolated linear, q values with a cubic spline. + + Drawing w over q gives you the discharge table at the given km. + + !!! This code needs testing !!! + +2011-04-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Added dependency to Apache Commons Math 2.2 (Apache License 2.0) + +2011-04-20 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Fix problem when sorting by q (copied w instead of q). + +2011-04-20 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Fixed broken HQL statement. + +2011-04-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + add a method interpolateW() which takes an array of + q values and returns an equal sized array of w values. + This is essentially the "Wasserstand/Wasserspiegellagen" calculation + of desktop FLYS. + + If you want to do a calculation with given w values you have + to convert the w values with DischargeTables.getQForW() first. + + !!! This code needs heavy testing !!! + +2011-04-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + We need a getQForW() method and not getWForQ() because when + doing a "Wasserstand/Wasserspiegellagen" calculation with given + w values these values need to be translated to q values with + the master discharge table. + +2011-04-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Sorting of q values was done wrong. + +2011-04-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + Ordered the list of annotations returned by this factory based on its + range. + +2011-04-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java: + New. This service returns an XML document that includes the main values + of a gauge based on a river name, a start and an end point. + + * doc/conf/conf.xml: Registered the MainValuesService. + +2011-04-19 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java: + A factory that provides methods to return MainValues. + +2011-04-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Added static method getWForQ() to interpolate a w value for + a given q value based on a given discharge table. + +2011-04-19 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Added convenience constructors/methods to ease the access to the master + discharge table of a gauge. + +2011-04-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Moved the query complexity into view 'wst_value_table' and + used this instead. + +2011-04-18 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Fetches w/q value tables from the backend. TODO: Move this + to the backend and use a view. + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Changed + the error key that is thrown if no input data was found so that the key + is usable for GWT's i18n mechanism. + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + The inserted river is validated now (overrides validate() of + DefaultState). + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + The inserted calculation method is validated now (overrides validate() + of DefaultState). + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + The input data of feed() are validated using the DefaultStates + validate() method. + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + New method validate() that needs to be overidden by concrete subclasses. + It should return true, if the data of the State is fine, otherwise it + should raise an exception. + + NOTE: The exceptions are not translated in the server but in the client! + + * src/main/java/de/intevation/flys/artifacts/states/RangeState.java: New. + This abstract class exists to provide some methods for handling ranges. + Currently, there is a method that validates a given range based on + min/max values. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Implemented input data validation for ranges. + + NOTE: The input validation of concrete values has not been implemented + yet! + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Removed debug code that has been commited by accident :-/ + +2011-04-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: The + getGauge() method returns the first gauge based on the given start and + end point of the river. + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + Fixed potential bugs: if no gauge could be determined, the default + values for W and Q are the minimum and maximum double values. + +2011-04-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: Fills + the DESCRIBE with default values for W and Q. + +2011-04-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WstFactory.java: + New. Returns Wst object - based on a river. + +2011-04-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Now + provides some methods that return some basic objects inserted while + parameterization: River, Gauge and so on. + +2011-04-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java, + src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + Bugfix: Repaired broken imports of the SessionHolder. + +2011-04-15 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/SessionHolder.java: + Moved this class to flys-backend. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java, + src/main/java/de/intevation/flys/artifacts/model/GaugesFactory.java, + src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java, + src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java: + Adapted imports of the SessionHolder. + +2011-04-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * trunk/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java, + trunk/src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + Acquire/release sessions in services to avoid db connection leaks. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Changed some method signatures - added a reference to the owner + Artifact. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/WQSelect.java, + src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Modified method signatures based on the changes in DefaultState. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + Added default values to the dynamic part of DESCRIBE. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Added a function that returns a River object based on a given river + name. + +2011-04-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java, + src/main/java/de/intevation/flys/artifacts/model/GaugesFactory.java, + src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java, + src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + Static methods are using the SessionHolder, too. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java: + Added the setup() method that has been added to the interface + description in the last commits. + + * doc/conf/conf.xml: Registered the SessionCallContextListener as + CallContext.Listener. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/SessionHolder.java: + Bugfix: Call correct method to retrieve an instance of + SessionFactoryProvider. + +2011-04-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/SessionHolder.java: + New. Contains thread local session holder for hibernate sessions. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Uses session from SessionHolder. + + * src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java: + Interacts with SessionHolder now. + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + Removed superfluous import. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java: + Implementation of a CallContext.Listener to open/close Hibernate + Sessions for each request. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Some modifications related to the last commit - modification of the + describe() signature of a State. + +2011-04-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/GaugeSelect.java: + Removed. We do not need a state to select a gauge - the selection takes + place by choosing a start and an end point. + +2011-04-13 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + Bugfix: added missing label node to root node and a namespace to the + data node. + +2011-04-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + The name of the artifact 'winfo' is written into the DESCRIBE document + now. We need this to have a proper way to distinguish between different + artifacts in the UI. + +2011-04-12 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Bugfix: + States are filled with data before they describe themself. + +2011-04-11 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: + New. A factory that returns the annotations of a specific river. + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + New. This service provides a document that contains information about + distances of a river. + + * doc/conf/conf.xml: Registered the DistanceInfoService. + +2011-04-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + This collection overrides the out() operation now. The incoming request + document is read and the related OutGenerator is used to create the + output. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed + the code to create discharge curves. It has moved to the + DischargeCurveGenerator which now does this work. + +2011-04-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: The + generate() method throws an IOException now. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java: + New. This OutGenerator creates discharge curves. + +2011-04-06 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Changed + the visibility of the getData() method. It's now public, because the + OutGenerator needs an artifact's data. + +2011-04-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/**/*.java: Removed trailing whitespace. + +2011-04-03 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Make project compilable again by + commenting out a not existing XMLDebug reference. + +2011-03-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Added code to parse the configured OutGenerators and to save them (in a + map) in the FLYSContext. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: + Added a key that is used to save the OutGenerators Map in the context. + +2011-03-31 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/OutGenerator.java: + New. This interface is used to generator different types of output. + ArtifactCollections will make use of this interface to create a + collected output of all its artifacts. + +2011-03-30 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Removed the Backend from FLYSArtifactCollection - used ArtifactDatabase + operations instead. + + * TODO: Removed 'remove Backend reference' TODO. + +2011-03-30 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Enhanced the configuration of the + discharge curve output mode. This output now provides three facets - W, + Q and the curve itself. + +2011-03-30 Ingo Weinzierl <ingo@intevation.de> + + Tagged RELEASE 0.1 + +2011-03-30 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Renamed an output mode in the WINFO + artifact configuration. + +2011-03-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: Changed a german string. + +2011-03-29 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Modified the available calculation modes and its order in the DESCRIBE + document. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Adapted the names of + calculation modes. + +2011-03-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added the hash code of an artifact to the artifact part of the + collection's DESCRIBE document. + +2011-03-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Changed + the background color of discharge curves to white. + +2011-03-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Cache the scale, too. Otherwise two calls to getValues() with + different arguments will result in the same output. + +2011-03-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Introduced a 'scale' parameter in the getValues() method. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Filled + the out() operation with code that draws a discharge table of one or + more gauges specified by the given range in entered in a previous state. + +2011-03-28 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/ChartExportHelper.java: + New. A helper class to exports charts. + + * pom.xml: Added dependencies to iText, Batik and JFreeChart. + +2011-03-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/importer/PegelGltParser.java: + Fixed swap of operands. + +2011-03-28 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/GaugesFactory.java: + New. Load gauges for a river and filter them for given + ranges. + +2011-03-25 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + Store data in a double [][] instead of interleaved double [] + to be compatible with org.jfree.data.xy.DefaultXYDataset. + +2011-03-25 Ingo Weinzierl <ingo@intevation.de> + + * TODO: Removed 'i18n' and 'step-back' TODOs and added an issue to remove + the Backend reference from FLYSArtifactCollection. + +2011-03-25 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + Added missing artifact namespace of an attribute in the DESCRIBE + document. + +2011-03-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java: + New. This ArtifactCollection overrides the DefaultArtifactCollection to + implement FLYS specific describe() and out() operations. + + * doc/conf/conf.xml: Use the FLYSArtifactCollection instead of the + DefaultArtifactCollection for this application. + +2011-03-24 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java: + New. Fetches values of discharge tables in form of packed + w/q double arrays for given gauges. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Removed needless import. + +2011-03-24 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages_de_DE.properties: Added a german resource + bundle to avoid exceptions in the flys artifacts. Sometimes, the + Resources class is not able to find a 'de_DE' bundle and throws an + exception. This is really strange, because it should use the 'de' bundle + in that case, but it doesn't. + +2011-03-23 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added + some code to append the output modes of previous states to the DESCRIBE + document. + + TODO: Determine if the current state is already filled with data and + append its output modes as well! + +2011-03-22 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Enhanced the location_distance state with + an output mode 'discharge_table'. + +2011-03-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Write human readable strings as label attribute into the DESCRIBE + output. Those labels are used to be displayed in the GUI. + +2011-03-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + Added some further calculation types. + + * src/main/resources/messages.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for the + calculation types + +2011-03-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Implemented the step-back part of the advance() operation. + +2011-03-21 Ingo Weinzierl <ingo@intevation.de> + + * src/main/resources/messages_de.properties: Fixed a german umlaut. + +2011-03-18 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Added new states for entering a + location/distance and w/q. + + * src/main/resources/messages.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: New string for the + location/distance and w/q input states. + +2011-03-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQSelect.java: + New. A state for the W/Q input of the WINFO parameterization. + +2011-03-18 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Append an attribute 'uiprovider' to the dynamic UI node. + + * src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java: + New. A state for the location/distance selection of the WINFO + parameterization. + +2011-03-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added a new method getUIProvider() that might be overriden by concreted + subclasses that should be rendered with a specific UIProvider. + +2011-03-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + The static UI part is created by the previous states now. This makes it + possible to group the data objects (which is necessary to group the + objects in the ui). + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Added a describeStatic() method that creates a node that contains the + data of that state. + +2011-03-17 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + Removed TODO: the document contains the rivers provided by the backend + now. + +2011-03-17 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * pom.xml: Added dependency to flys backend. + + * src/main/java/de/intevation/flys/artifacts/model/River.java: + Removed. We are using the backend model now. + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java: + Fetches the rivers from the backend. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + Import fixes. + +2011-03-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * doc/conf/conf.xml: Added section for database backend configuration. + +2011-03-15 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + Fixed build error coming from different import of XMLUtils. + +2011-03-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Appended the missing label node that contains the human readable name of + the data item. + +2011-03-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java, + src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + I18N of strings for the DESCRIBE document. + + * src/main/resources/messages.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: I18N strings for the + calculcation mode state. + +2011-03-14 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Modified the winfo states. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Adapted + the artifact regarding the changes of the last commit. The states + describe() method creates the dynamic UI node - the artifact needs to + apply this node. + + * src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java: + New. The state for choosing the calculation mode. + + * src/main/resources/messages.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added i18n strings for the + calculation mode state. + +2011-03-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + New. This is the base state for the FLYS application. It provides a + method that creates the dynamic ui node for the DESCRIBE. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeSelect.java: Both + classes extend the abstract base class DefaultState. + +2011-03-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/resources/Resources.java: + New. This class retrieves the i18n strings from a ResourceBundle. + + * src/main/resources/messages.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Resource files for german and + english translation. + +2011-03-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Appended + the data that have been inserted in former states into the static node + of the DESCRIBE. + +2011-03-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: The + operations feed() and advance() return the description of the artifact + using the describe() operation. This avoids additional server round trips + in the client - the clients gets to know about the new state of the + artifact immediately. + +2011-03-10 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Implemented a part (step forward) of the advance operation. + + * TODO: Implement Step-Back in advance operation. + +2011-03-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Implemented the abstract method getName(). It returns the constant + 'winfo' string. + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Implemented the feed action. The data of an incoming feed() operation is + stored in StateData objects that are saved in a map in the artifact. + + NOTE: There is no input validation and no i18n of error messages (see + TODO). + +2011-03-09 Ingo Weinzierl <ingo@intevation.de> + + * TODO: This file contains some open points that need to be done. + +2011-03-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: New. This + artifact serves as the default artifact for the FLYS application. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: This + artifact now inherits from FLYSArtifact. Furthermore, there is one big + change: we don't store the State objects itself in the artifact, but + just the identifier of those. This makes the artifact smaller and more + compatible agains previous versions of the software. + +2011-03-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/RiverService.java: + New. This service will retrieve a list of provided rivers. + + * doc/conf/conf.xml: Added a configuration for the RiverService. + +2011-03-07 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: Added a section user-factory and collection-factory in + the factories part of the configuration. + +2011-03-01 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + Replaced the 'special' attribute from DESCRIBE with a 'uiprovider' + attribute. + +2011-02-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The + RiverSelect state is called to create the UI part of the describe + document. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java: + Implemented the dynamic UI part of describe(). The static part is not + inserted into the describe document at the moment. We need a reference to + the previous states for this. + +2011-02-08 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java, + src/main/java/de/intevation/flys/artifacts/model/River.java: New. A model + class that represents a river and its factory to create concrete river + instances. + NOTE: Currently, this is just a mockup. The factory just returns two + static rivers "Mosel" and "Saar" without a connection to a backend. + +2011-02-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/StateFactory.java: The + input data of a state is initialized with empty StateData objects after + the State has been created. + + * doc/conf/artifacts/winfo.xml: Renamed the input data nodes of the states + which now fits better to the class name of the implementation. + +2011-02-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The + describe document returned by this artifact now contains the current state + and the reachable states. + +2011-02-07 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + The transitions are put into the TransitionEngine with the ID of the state + - not longer with the artifact name. On this way, we are able to fetch + just the transitions for a specific state, instead of all the transitions + of an artifact. + +2011-02-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Describe() + returns the artifact's uuid and hash value. The whole implementation of + describe() is still outstanding. + +2011-02-04 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/artifacts/winfo.xml: Removed useless config stuff. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed + useless methods, and improved the init process - the first state is set as + the current state for this artifact. + + * src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java, + src/main/java/de/intevation/flys/artifacts/states/GaugeSelect.java: New. + The states are used in the first two steps of the WINFOArtifact. + Currently, they just implement stubs of the necessary methods setup() and + describe(). + +2011-02-04 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/State.java, + src/main/java/de/intevation/flys/artifacts/transitions/TransitionEngine.java, + src/main/java/de/intevation/flys/artifacts/transitions/Transition.java: + Removed. These classes are placed in the artifact-database now. + + * src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java, + src/main/java/de/intevation/flys/artifacts/transitions/TransitionFactory.java: + Adapted imports of Transition. + + * src/main/java/de/intevation/flys/artifacts/states/StateFactory.java: New. + This factory should be used to create concrete State objects. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: Added + a constant key to store the StateEngine in the context. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + New method that initializes the states at application start. + +2011-02-03 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/State.java: New. The + interface description of a state. + + * src/main/java/de/intevation/flys/artifacts/transitions/Transition.java, + src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java: + New. The interface description and a default implementation of a + transition. + + * src/main/java/de/intevation/flys/artifacts/transitions/TransitionEngine.java: + New. The TransitionEngine stores all transitions for each artifact and + should be used to determine, if an artifact can advance from one state to + another. + + * src/main/java/de/intevation/flys/artifacts/transitions/TransitionFactory.java: + New. Transitions should be created by using this class. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java: New. + The Flys context. It currently defines keys to store important components + in the context. + + * src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java: + New. The context factory initializes the basic components of the + application. Currently, the TransitionEngine is created and all artifacts + with its transitions are read from the global configuration and stored in + the FLYSContext. + + * pom.xml: Added a dependency to the 'artifacts-common' package. + + * doc/conf/artifacts/winfo.xml: Corrected the classname of the + DefaultTransition. + + * doc/conf/conf.xml: Added FLYSContextFactory as context-factory. + +2011-02-02 Ingo Weinzierl <ingo@intevation.de> + + * doc/conf/conf.xml: An initial configuration file for the FLYS artifact + server. + + * doc/conf/artifacts/winfo.xml: An initial transition configuration of an + WINFO artifact. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: A stub of + an artifact for a WINFO parameterization. + + * pom.xml: Set the source code version to 1.5. + +2011-02-01 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/**, pom.xml: Added initial maven project. + * ChangeLog: new.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/Changes Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,310 @@ +2011-09-19 RELEASE 2.5 + + NEW: + + * Introduced the concept of a "datacage": the datacage is a service that + provides a list of chart themes that fit to a given chart type. The + service accepts a user uuid, the uuid of a master Artifact, the name + of the output type and a set of further string parameters. In general, + we distinguish between user-specific datacage and system-specific + datacage: + The user-specific datacage returns themes provided by old + calculations computed by the user. + The system-specific datacage returns themes that might be generated + using the data stored in the flys-backend. + + * Introduced a database used by the datacage that stores information + about Artifacts, their outputs and their facets. This database + requires synchronization with the Artifact database. The intent of + this database is to have a fast access to data stored in Artifacts. + + * Introduced a mechanism to clone existing Artifacts (with or without + restrictions). For cloning an Artifact, it is necessary to specify the + UUID of a "model Artifact". The clone will be based on that model by + extracting all required data from it. + + * Introduced "recommendations": recommendations are themes in charts or + maps (Artifacts/Facets) that should be added automatically to an + existing chart/map. They are provided by the datacage. + + * Introduced new Artifact types to provide further chart themes: + - Annotations + - Mainvalues + + * Introduced new Facet type WMSLayerFacet. This type stores all required + information (server url, layer names, layer extent, layer srid) to + display a WMS layer in a WMS client. + + * Introduced a new chart output "Querprofildiagramm". This output + calculates a waterlevel and displays it as single line together with + one or more cross section lines ("Querprofilspuren"). + + * Introduced a new chart output "W-Differenzen". This output calculates + waterlevel differences based on at least two waterlevels (a + "W-Differenzen" output can consist of more than a single waterlevel + difference calculation). Each waterlevel difference calculation + results in three chart themes: two W curves and a W-Differences curve. + + * Introduced a new output "Überschwemmungskarte". The visualization of + this output is a map. One of the map's layers is a WMS layer that + displays the calculation result of WSPLGEN (external C++ tool). + + * Improved the rendering process of chart themes: the styles configured + for themes are now used. + + * Improved the DistanceInfoService: it supports filters to filter the + type of items returned by this service (reduces the number of returned + items of course). + + * Introduced a CSV export for "W-Differenzen". + + * Downgraded GNU Trove to 1.1-beta-5 (later versions have been removed + from maven repositories). + + + FIXES: + + * flys/issue135 (Diagramm: Trotz abgeschalteter Themen bleiben Beschriftungen bestehen) + + * flys/issue159 (WINFO: Radiobutton - Ortsauswahl bei "W für ungleichwertigen Abflusslängsschnitt" entfernen) + + * flys/issue160 (WINFO: Auswahltabelle Orte bei Modus Strecke nach Step-Back) + + * flys/issue176 (Diagramm: Benennung eines Abflusses bei gewählter Höhe am Pegel) + + * flys/issue180 (WINFO: Zeilen der Tabelle können nach der Markierung in die Zwischenablage kopiert werden.) + + * flys/issue181 (Erstes Thema in der Themenliste wählt sich automatisch wieder an) + + * flys/issue191 (AT-Export: Längsten monoton steigenden Bereich exportieren.) + + * flys/issue219 (W-INFO: Abflusskurvenberechnung / keine Themen im Diagramm) + + * flys/issue254 (Datenkorb: Klonen von Artefakten in anderen Collections + Facettenfilter zum Ausblenden) + + * flys/issue256 (Datenkorb: XXX Issue festhalten) + + * flys/issue258 (Datenkorb: Outs statt States führen) + + * flys/issue259 (Daten aus Datenkorb in Diagramm einladen) + + * flys/issue260 (Datenkorb: Masterartefakt in View aufführen) + + * flys/issue262 (Datenkorb: Vereinigung der beiden Konfigurations-Templates) + + * flys/issue279 (WINFO: Elbe Wasserspiegellage - Index Out of Bounds) + + * flys/issue280 (BoundingBoxen von Streckenfavoriten und Haupt- und Extremwerten unsichtbar machen) + + * flys/issue281 (Karte: Auswahl der berechnten Wasserspiegellage über Inline-Datenkorb) + + * flys/issue282 (Karte: Abstand interpolierte Profile - Default wert) + + * flys/issue290 (Karte: Eingabe von Differenzen zw. WSP und Gelände findet keine Ausprägung in der Karte) + + * flys/issue303 (Keine Streckenfavoriten, wenn nur Q im Längsschnittdiagram ausgewählt) + + * flys/issue309 (Querprofil: Manuelle Eingabe funktioniert nicht nach Return (nur nach Tab)) + + * flys/issue310 (Querprofil: Farben der Themen) + + * flys/issue311 (Querprofil: i18n) + + + +2011-06-27 RELEASE 2.4 + + NEW: + + * Finalized the Facet concept: output modes and the output generation + are now based on facets. Facets are created dynamically by an Artifact + based on the results of a calculation. + + * Introduced a report mechanism that gives feedback of calculation + problems. + + * Introduced output modes that generate XML document with calculation + report information. + + * Introduced deactivated themes in charts: such themes are not rendered. + + * Introduced a cache to store distance info per river. + + * Introduced output modes that generate XML documents which contain meta + information of charts as axes ranges, data ranges and a transformation + matrix that allows to transform image coordinates into chart + coordinates. + + * Added support for zoom values in Chart output modes. + + * Added support for min/max values in DESCRIBE documents. + + * Added "Oberkante" and "Unterkante" columns to distance info service. + + * Added a new export mode to save data in AT format. + + * Improved performance while storing/loading Q values of WST columns. + + * Improved the WQ values validation for calculation 1 & 4. + + * Improved calculations to work independent of "from"/"to" order of + kilometer ranges. + + * Improved the input of WQ values for calculation 1. We distinguish + between a selected Q at a given gauge or a selected Q that doesn't + base on a given gauge. + + * Allow "from" to be greater than "to" in kilometer ranges. + + * Write default values of the user into the Artifact's DESCRIBE + document (flys/issue40). + + + FIXES: + + * flys/issue62 Artifacts no longer share their data with each other. + + * flys/issue77 Added titles for themes in duration curve charts. + + * flys/issue81 + + * flys/issue82 Fixed NPE after a calculation has taken place. + + * flys/issue84 + + * flys/issue85 Fixed location input for calculation 1 & 4. + + * flys/issue86 Fixed Q determination based on a given W. + + * flys/issue90 Removed space between chart axes and chart area. + + * flys/issue93 Renamed calculation 4. + + * flys/issue103 Append values selected by the user in the correct format + to the DESCRIBE document of Artifacts (uses i18n). + + * flys/issue147 + + * flys/issue150 Invert the X axis correctly for charts of type + calculation 1 & 4. + + * flys/issue154 Repaired computed discharge curve that broke after the + facets had been finalized. + + * flys/issue157 Discharge curve charts (computed an static) will now + have a lower x value set to "1". + + * flys/issue161 Longitudinal section chart's second Y axis will + initially start at Q=0. + + * flys/issue164 Improved input validation for WQ input of calculation 4. + + * flys/issue172 Duration curve charts will now have a lower x value set + to "0". + + * flys/issue173 Fixed broken gauge determination in calculation 4. + + * flys/issue174 Repaired broken upper margin between chart data and + chart border in longitudinal section charts. + + * Added missing "Corrected W" facet for results of calculation 4. + + * Map datasets in duration curve charts to the correct axes. + + * Fixed broken XPath to detect output modes in an attribute document of + a Collection. + + * Feed operation will no longer save data if the validation of the given + values failed. + + + +2011-05-19 RELEASE 2.3.1 + + NEW: + + * New export format for waterlevels: WST. + + * Added descriptions for the curves of the following charts: + - discharge curves (dt. 'Abflusskurven am Pegel') + - computed discharge curves (dt. 'berechnete Abflusskurven') + - longitudinal section curves (dt. 'Längsschnitt') + - discharge longitudinal section curves (dt. 'Abflusslängsschnitt') + + * Number formatting is done in a central place/class. + + FIXES: + + * flys/issue47 (Diagramm: Farbliche Unterscheidung von Abfluß und Wasserstand) + + * flys/issue52 (WINFO: W-Längsschnitt - Wasser jeweils von links nach rechts laufen lassen) + + * flys/issue53 (WINFO/Berechnungsausgabe: Kilometerierung und Wasserstände werden zum Teil mit vielen Nachkommastellen angezeigt) + + * flys/issue66: (i18n: Untertitel bei Längsschnitten - Bereich der Strecke enthält "double") + + * flys/issue67 (WINFO: Längsschnitt - Wasser fließt bergauf) + + * flys/issue72: (WINFO: Q/W/D-Info liefert selten eine Antwort) + + + +2011-05-13 RELEASE 2.3 + + NEW: + + * Initial release of the artifacts for FLYS. Currently there is a single + WINFO artifact for the following computations: + - waterlevels + - discharge curves + - duration curves + - discharge longitudinal section curves + + * Configuration is placed in doc/conf/conf.xml + + * WINFO Artifact specific configuration is placed in + doc/conf/artifacts/winfo.xml + + * So called 'OutGenerators' produce different types of output. + Currently, the flys-artifacts are able to produce charts and exports. + Each output type has to be configured in conf.xml. + + * New chart types: + - discharge curves (dt. 'Abflusskurven am Pegel') + - computed discharge curves (dt. 'Abflusskurve') + - longitudinal section curves (dt. 'Längsschnitte') + - duration curves (dt. 'Dauerlinie') + - discharge longitudinal section curve (dt. 'W bei + ungleichmäßigem Abflusslängsschnitt') + + * New exports: + - csv of waterlevels + - csv of duration curves + - csv of computed discharge curves + - csv of discharge longitudinal section + + * New services that provides: + - supported rivers + - main values of a gauge + - range information of a river + - meta information of a river + + * Caching of computation relevant values + + * Initial model to support chart specific themes (theme.xml) + + + LIMITATIONS: + + * Charts are not rendered using the themes in theme.xml + + + !!! + + The version number of this release depends on an existing desktop variant of + this software that is in version 2.1. + + !!! + + +2011-03-30 RELEASE 0.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/NEWS Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,13 @@ +NEWS + +for enduser-specific information, c.f. the NEWS -file in the module flys-client + +2011-05-19 Release V 2.3.1 + * Bugfixing Release for WINFO + +2011-05-16 Release V 2.3.0 + * Enhanced functionality for WINFO, diagram and Data-Manager (Datenkorb) + +2011-03-27 Release V 2.2 + +This file starts with V. 2.2. Earlier versions are based on a Desktop-version until V 2.1.3.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/TODO Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1 @@ +- Validation of the input values of an incoming feed() call
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/contrib/add-i18n-numbers.py Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +""" Add unique numbers in front of properties values + to identfy the key without knowing the real key. +""" + +import sys +import re +import os + +BLACK_LISTED_KEYS = [ + re.compile(r".*\.file$") +] + +BLACK_LISTED_VALUES = [ + re.compile(r"^http.*$") +] + +NUMBERED = re.compile(r"^\s*([^\s]+)\s*=\s*\[([0-9a-zA-Z]+)\]\s*(.+)$") +UNUMBERED = re.compile(r"^\s*([^\s]+)\s*=\s*(.+)$") + +ALPHA = "0123456789" \ + "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +def decode_ibase62(s): + t, c = 0, 1 + for x in s[::-1]: + i = ALPHA.find(x) + t += i*c + c *= len(ALPHA) + return t + +def ibase62(i): + if i == 0: + return "0" + out = [] + if i < 0: + out.append("-") + i = -1 + while i > 0: + out.append(ALPHA[i % len(ALPHA)]) + i //= len(ALPHA) + out.reverse() + return ''.join(out) + +def is_blacklisted(key, value): + + for bl in BLACK_LISTED_KEYS: + if bl.match(key): + return True + + for bl in BLACK_LISTED_VALUES: + if bl.match(value): + return True + + return False + +def find_key(already_numbered, value): + for k, v in already_numbered.iteritems(): + if v == value: + return k + return None + +def decorated_content(infile, outfile, already_numbered): + + for line in infile: + line = line.strip() + m = NUMBERED.match(line) + if m: + key, num, value = m.groups() + decoded_num = decode_ibase62(num) + last = find_key(already_numbered, decoded_num) + if last is None: + already_numbered[key] = decoded_num + elif last != key: + print >> sys.stderr, "WARN: Number clash: " \ + "%s leeds to '%s' and '%s'" % (num, key, last) + print >> outfile, line + continue + + m = UNUMBERED.match(line) + if m: + key, value = m.groups(1) + if is_blacklisted(key, value): + print >> outfile, line + else: + num = already_numbered.setdefault(key, len(already_numbered)) + print >> outfile, "%s=[%s] %s" % (key, ibase62(num), m.group(2)) + continue + print >> outfile, line + +def tmp_fname(fname): + name = fname + ".tmp" + i = 0 + while os.path.exists(name): + name = "%s.tmp%d" % (fname, i) + i += 1 + return name + +def decorate_file(fname, already_numbered): + + tmp = tmp_fname(fname) + + with open(fname, "r") as infile: + with open(tmp, "w") as outfile: + decorated_content(infile, outfile, already_numbered) + + os.rename(tmp, fname) + +def main(): + already_numbered = {} + for fname in sys.argv[1:]: + print >> sys.stderr, "checking %s" % fname + decorate_file(fname, already_numbered) + +if __name__ == "__main__": + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/contrib/check-i18n-properties.py Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +import sys +import re + +SPLIT_RE = re.compile(r"^\s*([^=]+)=\s*(.*)\s*") + +def load_properties_file(filename): + props = {} + with open(filename, "r") as f: + while True: + line = f.readline() + if not line: break + m = SPLIT_RE.match(line) + if not m: continue + k = m.group(1).strip() + v = m.group(2).strip() + if k in props: + print >> sys.stderr, "'%s' found more than once in '%s'." % ( + k, filename) + else: + props[k] = v + return props + +def main(): + + props = [(arg, load_properties_file(arg)) for arg in sys.argv[1:]] + + l = len(props) + + for i in range(0, l): + a = props[i][1] + for j in range(i+1, l): + b = props[j][1] + for k in a.iterkeys(): + if k not in b: + print >> sys.stderr, "'%s' found in '%s' but not in '%s'." % ( + k, props[i][0], props[j][0]) + for k in b.iterkeys(): + if k not in a: + print >> sys.stderr, "'%s' found in '%s' but not in '%s'." % ( + k, props[j][0], props[i][0]) + +if __name__ == '__main__': + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/contrib/fixoverview2html.xsl Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,397 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet + version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:output method="xml" encoding="UTF-8" + doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" + doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="yes"/> + + <xsl:param name="project-uuid">de3f3307-3429-4ff9-8f43-3fb2fcf21b27</xsl:param> + <xsl:param name="render-checkboxes" select="true()"/> + <xsl:param name="callback"/> + + <xsl:param name="locale">de</xsl:param> + + <xsl:decimal-format name="de" decimal-separator=',' grouping-separator='.'/> + <xsl:decimal-format name="en" decimal-separator='.' grouping-separator=','/> + + <!-- XXX: This kind of i18n is cheesy. + It should be better done in an external resource. --> + + <xsl:variable name="km-pattern"> + <xsl:choose> + <xsl:when test="$locale = 'de'">0,##</xsl:when> + <xsl:otherwise>0.##</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-event"> + <xsl:choose> + <xsl:when test="$locale = 'de'">Ereignis</xsl:when> + <xsl:otherwise>Event</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-legend"> + <xsl:choose> + <xsl:when test="$locale = 'de'">Legende</xsl:when> + <xsl:otherwise>Caption</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-color"> + <xsl:choose> + <xsl:when test="$locale = 'de'">Farbe</xsl:when> + <xsl:otherwise>Color</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-meaning"> + <xsl:choose> + <xsl:when test="$locale = 'de'">Bedeutung</xsl:when> + <xsl:otherwise>Meaning</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-around-mnq"> + <xsl:choose> + <xsl:when test="$locale = 'de'">um MNQ</xsl:when> + <xsl:otherwise>around MNQ</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-around-mq"> + <xsl:choose> + <xsl:when test="$locale = 'de'">um MQ</xsl:when> + <xsl:otherwise>around MQ</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-around-mhq"> + <xsl:choose> + <xsl:when test="$locale = 'de'">um MHQ</xsl:when> + <xsl:otherwise>around MHQ</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="i18n-above-hq5"> + <xsl:choose> + <xsl:when test="$locale = 'de'">über HQ5</xsl:when> + <xsl:otherwise>above HQ5</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <!-- TODO: Format dates according locale. --> + + <xsl:template match="@*" mode="min"> + <xsl:if test="position() = 1"> + <xsl:value-of select="number(.)"/> + </xsl:if> + </xsl:template> + + <xsl:template match="@*" mode="max"> + <xsl:if test="position() = last()"> + <xsl:value-of select="number(.)"/> + </xsl:if> + </xsl:template> + + <xsl:variable name="global-min"> + <xsl:choose> + <xsl:when test="count(/fixings/events/event/sector) > 0"> + <xsl:apply-templates mode="min" select="/fixings/events/event/sector/@from"> + <xsl:sort data-type="number" select="."/> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number(/fixings/river/@from)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="global-max"> + <xsl:choose> + <xsl:when test="count(/fixings/events/event/sector) > 0"> + <xsl:apply-templates mode="max" select="/fixings/events/event/sector/@to"> + <xsl:sort data-type="number" select="."/> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number(/fixings/river/@to)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:template name="percent"> + <xsl:param name="sector"/> + + <xsl:variable name="start"> + <xsl:choose> + <xsl:when test="number($sector/@from) < $global-min"> + <xsl:value-of select="$global-min"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number($sector/@from)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="end"> + <xsl:choose> + <xsl:when test="number($sector/@to) > $global-max"> + <xsl:value-of select="$global-max"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number($sector/@to)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$end < $start"> + <xsl:value-of select="number(0)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="100.0 * (($end - $start) div ($global-max - $global-min))"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="emit-gap-gauge"> + <xsl:param name="gauge"/> + <xsl:call-template name="internal-emit-gap"> + <xsl:with-param name="sector" select="$gauge"/> + <xsl:with-param name="preds" select="$gauge/preceding-sibling::gauge"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="emit-gap"> + <xsl:param name="sector"/> + <xsl:call-template name="internal-emit-gap"> + <xsl:with-param name="sector" select="$sector"/> + <xsl:with-param name="preds" select="$sector/preceding-sibling::sector"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="internal-emit-gap"> + <xsl:param name="sector"/> + <xsl:param name="preds"/> + + <xsl:variable name="start"> + <xsl:choose> + <xsl:when test="number($sector/@from) < $global-min"> + <xsl:value-of select="$global-min"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$sector/@from"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:if test="$start < $global-max"> + <xsl:variable name="num-preds" select="count($preds)"/> + <xsl:variable name="prev-end"> + <xsl:choose> + <xsl:when test="count($preds) < 1"> + <xsl:value-of select="$global-min"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number($preds[last()]/@to)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:if test="$prev-end < $global-max"> + <xsl:variable name="gap-len" select="$start - $prev-end"/> + <xsl:if test="$gap-len > 0.005"> + <div> + <xsl:attribute name="style"> + <xsl:text>width:</xsl:text> + <xsl:value-of select="100.0 * ($gap-len div ($global-max - $global-min))"/> + <xsl:text>%;float:left</xsl:text> + </xsl:attribute> + <xsl:text disable-output-escaping="yes"><![CDATA[ ]]></xsl:text> + </div> + </xsl:if> + </xsl:if> + </xsl:if> + </xsl:template> + + <xsl:template match="sector" mode="sectors"> + <xsl:call-template name="emit-gap"> + <xsl:with-param name="sector" select="."/> + </xsl:call-template> + <div> + <xsl:attribute name="style"> + <xsl:text>background:</xsl:text> + <xsl:choose> + <xsl:when test="@class = '0'">green</xsl:when> + <xsl:when test="@class = '1'">blue</xsl:when> + <xsl:when test="@class = '2'">magenta</xsl:when> + <xsl:when test="@class = '3'">red</xsl:when> + <xsl:otherwise>black</xsl:otherwise> + </xsl:choose> + <xsl:text>;width:</xsl:text> + <xsl:call-template name="percent"> + <xsl:with-param name="sector" select="."/> + </xsl:call-template> + <xsl:text>%</xsl:text> + <xsl:text>;float:left</xsl:text> + </xsl:attribute> + <xsl:attribute name="title"> + <xsl:text>km </xsl:text> + <xsl:value-of select="format-number(@from, $km-pattern, $locale)"/> + <xsl:text> - </xsl:text> + <xsl:value-of select="format-number(@to, $km-pattern, $locale)"/> + <xsl:choose> + <xsl:when test="@class = '0'"> / Q <xsl:value-of select="$i18n-around-mnq"/></xsl:when> + <xsl:when test="@class = '1'"> / Q <xsl:value-of select="$i18n-around-mq"/></xsl:when> + <xsl:when test="@class = '2'"> / Q <xsl:value-of select="$i18n-around-mhq"/></xsl:when> + <xsl:when test="@class = '3'"> / Q <xsl:value-of select="$i18n-above-hq5"/></xsl:when> + </xsl:choose> + </xsl:attribute> + <xsl:text disable-output-escaping="yes"><![CDATA[ ]]></xsl:text> + </div> + </xsl:template> + + <xsl:template match="event"> + <tr id="{@cid}"> + <xsl:if test="$render-checkboxes"> + <td> + <input type="checkbox" name="{$project-uuid}:{@cid}" checked="true" onclick="{$callback}"/> + </td> + </xsl:if> + <td> + <xsl:apply-templates mode="sectors"/> + </td> + <td align="center"> + <xsl:attribute name="title"><xsl:value-of select="@description"/></xsl:attribute> + <xsl:value-of select="@date"/> + </td> + </tr> + </xsl:template> + + <xsl:template match="gauge" mode="gauges"> + <xsl:call-template name="emit-gap-gauge"> + <xsl:with-param name="gauge" select="."/> + </xsl:call-template> + <div> + <xsl:variable name="start"> + <xsl:choose> + <xsl:when test="number(@from) < $global-min"> + <xsl:value-of select="$global-min"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number(@from)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="end"> + <xsl:choose> + <xsl:when test="number(@to) > $global-max"> + <xsl:value-of select="$global-max"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number(@to)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:attribute name="style"> + <xsl:text>overflow:hidden;background:</xsl:text> + <xsl:choose> + <xsl:when test="(count(preceding::*) mod 2) = 0">#ada96e</xsl:when> + <xsl:otherwise>silver</xsl:otherwise> + </xsl:choose> + <xsl:text>;width:</xsl:text> + <xsl:call-template name="percent"> + <xsl:with-param name="sector" select="."/> + </xsl:call-template> + <xsl:text>%</xsl:text> + <xsl:text>;float:left</xsl:text> + </xsl:attribute> + <xsl:attribute name="title"> + <xsl:value-of select="@name"/> + <xsl:text>: km </xsl:text> + <xsl:value-of select="format-number($start, $km-pattern, $locale)"/> + <xsl:text> - </xsl:text> + <xsl:value-of select="format-number($end, $km-pattern, $locale)"/> + </xsl:attribute> + <nobr><xsl:value-of select="@name"/></nobr> + </div> + </xsl:template> + + <xsl:template match="events"> + <table width="97%" border="1" cellspacing="0" cellpadding="0" + style="font-size: 10pt;font-family:Arial;Verdana,sans-serif"> + <colgroup> + <xsl:if test="$render-checkboxes"> + <col width="20px"/> + </xsl:if> + <col width="*"/> + <col width="75px"/> + </colgroup> + <tr> + <xsl:if test="$render-checkboxes"> + <th> </th> + </xsl:if> + <th><xsl:apply-templates mode="gauges" select="/fixings/gauges"/></th> + <th><xsl:value-of select="$i18n-event"/></th> + </tr> + <xsl:apply-templates/> + </table> + </xsl:template> + + <xsl:template match="/"> + <html> + <head> + <title>Fixierungen:</title> + </head> + <body> + <xsl:apply-templates/> + <hr/> + <table border="1" cellspacing="0" cellpadding="0"> + <caption><xsl:value-of select="$i18n-legend"/></caption> + <tr> + <th><xsl:value-of select="$i18n-color"/></th> + <th colspan="2"><xsl:value-of select="$i18n-meaning"/></th> + </tr> + <xsl:if test="count(/fixings/events/event/sector[@class = '0']) > 0"> + <tr> + <td style="background: green"> </td> + <td><xsl:value-of select="$i18n-around-mnq"/></td> + <td>Q ∈ [0, (MNQ+MQ)/2)</td> + </tr> + </xsl:if> + <xsl:if test="count(/fixings/events/event/sector[@class = '1']) > 0"> + <tr> + <td style="background: blue"> </td> + <td><xsl:value-of select="$i18n-around-mq"/></td> + <td>Q ∈ [(MNQ+MQ)/2, (MQ+MHQ)/2)</td> + </tr> + </xsl:if> + <xsl:if test="count(/fixings/events/event/sector[@class = '2']) > 0"> + <tr> + <td style="background: magenta"> </td> + <td><xsl:value-of select="$i18n-around-mhq"/></td> + <td>Q ∈ [(MQ+MHQ)/2, HQ5)</td> + </tr> + </xsl:if> + <xsl:if test="count(/fixings/events/event/sector[@class = '3']) > 0"> + <tr> + <td style="background: red"> </td> + <td><xsl:value-of select="$i18n-above-hq5"/></td> + <td>Q ∈ [HQ5, ∞)</td> + </tr> + </xsl:if> + </table> + </body> + </html> + </xsl:template> + + <xsl:template match="text()"/> + <xsl:template match="text()" mode="sectors"/> + <xsl:template match="text()" mode="gauges"/> + +</xsl:stylesheet>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/contrib/themes2html.xsl Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet + version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:output method="xml" encoding="UTF-8" + doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" + doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="yes"/> + + + <xsl:template match="/themes/themegroup" mode="header"> + <li><a href="#tg-{@name}"><xsl:value-of select="@name"/></a> (<xsl:value-of select="count(theme)"/> themes)</li> + </xsl:template> + + <xsl:template match="field" mode="theme-inherits"> + <tr> + <td><i><xsl:value-of select="@name"/></i> (<a + href="#theme-{../../../@name}-{../../@name}"><xsl:value-of select="../../@name"/></a>)</td> + <td><xsl:value-of select="@display"/></td> + <td><xsl:value-of select="@type"/></td> + <td><xsl:value-of select="@default"/></td> + <td><xsl:value-of select="@hints"/></td> + </tr> + </xsl:template> + + <xsl:template match="field" mode="theme-fields"> + <tr> + <td><xsl:value-of select="@name"/></td> + <td><xsl:value-of select="@display"/></td> + <td><xsl:value-of select="@type"/></td> + <td><xsl:value-of select="@default"/></td> + <td><xsl:value-of select="@hints"/></td> + </tr> + </xsl:template> + + <xsl:template match="inherit" mode="theme-inherits"> + <xsl:variable name="target" select="@from"/> + <xsl:apply-templates + select="../../../theme[@name = $target]/inherits/inherit | /themes/themegroup/theme[@type='virtual' and @name=$target]/inherits/inherit" + mode="theme-inherits"/> + <xsl:apply-templates + select="../../../theme[@name = $target]/fields/field | /themes/themegroup/theme[@type='virtual' and @name=$target]/fields/field" + mode="theme-inherits"/> + </xsl:template> + + <xsl:template match="theme" mode="sub-themes"> + <xsl:variable name="tname" select="../@name"/> + <xsl:variable name="name" select="@name"/> + <li><a href="#theme-{$tname}-{$name}"><xsl:value-of select="$tname"/>/<xsl:value-of select="$name"/></a></li> + </xsl:template> + + <xsl:template match="theme" mode="theme-groups"> + <div> + <h4>[<a href="#theme-groups">Groups</a>] [<a href="#tg-{../@name}"><xsl:value-of select="../@name"/></a>] <a + name="theme-{../@name}-{@name}">Theme '<xsl:value-of select="@name"/>'<xsl:if + test="@type = 'virtual'"> (virtual)</xsl:if></a></h4> + + <xsl:variable name="tname" select="../@name"/> + <xsl:variable name="is-virtual" select="$tname = 'virtual'"/> + <xsl:variable name="name" select="@name"/> + + <xsl:if + test="count(/themes/themegroup[$is-virtual or @name=$tname or @name='virtual']/theme[inherits/inherit/@from=$name]) > 0"> + <strong>Sub themes</strong> + <ul> + <xsl:apply-templates + select="/themes/themegroup[$is-virtual or @name=$tname or @name='virtual']/theme[inherits/inherit/@from=$name]" + mode="sub-themes"/> + </ul> + </xsl:if> + + <table border="1" cellspacing="0" width="80%" summary="Definition of theme {@name}"> + <tr> + <th>Name</th> + <th>Display</th> + <th>Type</th> + <th>Default</th> + <th>Hints</th> + </tr> + <xsl:apply-templates mode="theme-inherits" select="inherits/inherit"/> + <xsl:apply-templates mode="theme-fields" select="fields/field"/> + </table> + </div> + <hr/> + </xsl:template> + + <xsl:template match="theme" mode="theme-list"> + <li><a href="#theme-{../@name}-{@name}"><xsl:value-of select="@name"/></a></li> + </xsl:template> + + <xsl:template match="/themes/themegroup" mode="theme-groups"> + <div> + <h2><a name="tg-{@name}">Theme group '<xsl:value-of select="@name"/>'</a></h2> + <div> + <h3>Theme List</h3> + <ul> + <xsl:apply-templates mode="theme-list" select="theme"/> + </ul> + </div> + <div> + <h3>Theme Definitions</h3> + <xsl:apply-templates mode="theme-groups" select="theme"/> + </div> + </div> + </xsl:template> + + <xsl:template match="mapping" mode="mappings"> + <xsl:variable name="target" select="@to"/> + <tr> + <td><xsl:value-of select="@from"/></td> + <td><a + href="#theme-{/themes/themegroup/theme[@name = $target][1]/../@name}-{$target}" + ><xsl:value-of select="@to"/></a></td> + <td><xsl:if test="@pattern"><pre><xsl:value-of select="@pattern"/></pre></xsl:if></td> + <td><xsl:if test="@masterAttr"><pre><xsl:value-of select="@masterAttr"/></pre></xsl:if></td> + </tr> + </xsl:template> + + <xsl:template match="mappings" mode="mappings"> + <div> + <h3><a name="mappings">Mappings</a></h3> + <table width="80%" border="1" cellspacing="0" summary="Mappings from facets to themes"> + <tr> + <th>From</th> + <th>To</th> + <th>Pattern</th> + <th>Condition</th> + </tr> + <xsl:apply-templates select="mapping" mode="mappings"/> + </table> + </div> + </xsl:template> + + <xsl:template match="/"> + <html> + <head> + <title>FLYS3 - Themes</title> + </head> + <body> + <h1>FLYS3 - Themes</h1> + <div> + <h2><a name="theme-groups">Theme groups</a> (<xsl:value-of select="count(/themes/themegroup)"/> groups)</h2> + <ul> + <xsl:apply-templates mode="header" select="/themes/themegroup[@name != 'virtual']"/> + <xsl:apply-templates mode="header" select="/themes/themegroup[@name = 'virtual']"/> + </ul> + </div> + <div> + <h2><a href="#mappings">Mappings</a> (<xsl:value-of select="count(/themes/mappings/mapping)"/> mappings)</h2> + </div> + <hr/> + <div> + <xsl:apply-templates mode="theme-groups" select="/themes/themegroup[@name != 'virtual']"/> + <xsl:apply-templates mode="theme-groups" select="/themes/themegroup[@name = 'virtual']"/> + </div> + <xsl:apply-templates mode="mappings" select="/themes/mappings"/> + </body> + </html> + </xsl:template> + + <xsl:template match="text()"/> + <xsl:template match="text()" mode="header"/> + <xsl:template match="text()" mode="theme-groups"/> + <xsl:template match="text()" mode="theme-list"/> + <xsl:template match="text()" mode="sub-themes"/> + <xsl:template match="text()" mode="theme-fields"/> + <xsl:template match="text()" mode="theme-inherits"/> + <xsl:template match="text()" mode="mappings"/> + +</xsl:stylesheet>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/contrib/visualize-transitions.xsl Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2010 by Intevation GmbH + + This program is free software under the LGPL (>=v2.1) + Read the file LGPL.txt coming with the software for details + or visit http://www.gnu.org/licenses/ if it does not exist. + + Author: Sascha L. Teichmann (sascha.teichmann@intevation.de) +--> + +<xsl:stylesheet + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.0"> + + <xsl:output method="text" encoding="UTF-8"/> + + <xsl:param name="base-dir">.</xsl:param> + + <xsl:template match="/"> + <xsl:text>digraph transition_model {
</xsl:text> + <xsl:apply-templates /> + <xsl:text>}
</xsl:text> + </xsl:template> + + <xsl:template match="artifact"> + <xsl:choose> + <xsl:when test="@xlink:href != ''"> + <!-- handle external artifacts --> + <xsl:variable name="path"> + <xsl:call-template name="string-replace-all"> + <xsl:with-param name="text" select="@xlink:href" /> + <xsl:with-param name="replace">${artifacts.config.dir}</xsl:with-param> + <xsl:with-param name="by" select="$base-dir" /> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="document($path)"> + <xsl:apply-templates select="/artifact"/> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <!-- handle internal artifacts --> + <xsl:text>subgraph </xsl:text><xsl:value-of select="@name"/> + <xsl:text> {
</xsl:text> + <xsl:text> label = "Artefakt: </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>";
</xsl:text> + <xsl:apply-templates mode="inside-artifact" select="./states/state"/> + <xsl:apply-templates mode="inside-artifact" select="./states/transition"/> + <xsl:text>}
</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="state" mode="inside-artifact"> + <xsl:text> "</xsl:text> + <xsl:value-of select="@id"/> + <xsl:text disable-output-escaping="yes" + >" [ shape = "record" label=<<table border="0" cellborder="0" cellpadding="3"> + <tr><td align="center" colspan="2" bgcolor="black"><font color="white"></xsl:text> + <xsl:value-of select="@id"/> + <xsl:text disable-output-escaping="yes" + ></font></td></tr></xsl:text> + <xsl:apply-templates mode="inside-artifact" /> + <xsl:text disable-output-escaping="yes" + ></table>>]</xsl:text> + <xsl:text>;
</xsl:text> + </xsl:template> + + <xsl:template match="data" mode="inside-artifact"> + <xsl:text disable-output-escaping="yes" + ><tr><td align="right"></xsl:text> + <xsl:value-of select="@name"/> + <xsl:text disable-output-escaping="yes" + ></td><td align="left"></xsl:text> + <xsl:value-of select="@type"/> + <xsl:text disable-output-escaping="yes" + ></td></tr></xsl:text> + </xsl:template> + + <xsl:template match="transition" mode="inside-artifact"> + <xsl:text> "</xsl:text> + <xsl:value-of select="from/@state"/> + <xsl:text disable-output-escaping="yes">" -> "</xsl:text> + <xsl:value-of select="to/@state"/> + <xsl:text>"</xsl:text> + <xsl:apply-templates mode="inside-artifact"/> + <xsl:text>;
</xsl:text> + </xsl:template> + + <xsl:template match="condition" mode="inside-artifact"> + <xsl:text> [ label="</xsl:text> + <xsl:value-of select="@data"/> + <xsl:text> </xsl:text> + <xsl:call-template name="readable-operator"> + <xsl:with-param name="operator" select="@operator"/> + </xsl:call-template> + <xsl:text> </xsl:text> + <xsl:value-of select="@value"/> + <xsl:text>" ]</xsl:text> + </xsl:template> + + <xsl:template match="text()" mode="inside-artifact"/> + <xsl:template match="text()"/> + + <xsl:template name="readable-operator"> + <xsl:param name="operator" /> + <xsl:choose> + <xsl:when test='$operator = "equal"'>=</xsl:when> + <xsl:when test='$operator = "notequal"'>!=</xsl:when> + <xsl:otherwise><xsl:value-of select="$operator"/></xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="string-replace-all"> + <xsl:param name="text" /> + <xsl:param name="replace" /> + <xsl:param name="by" /> + <xsl:choose> + <xsl:when test="contains($text, $replace)"> + <xsl:value-of select="substring-before($text,$replace)" /> + <xsl:value-of select="$by" /> + <xsl:call-template name="string-replace-all"> + <xsl:with-param name="text" + select="substring-after($text,$replace)" /> + <xsl:with-param name="replace" select="$replace" /> + <xsl:with-param name="by" select="$by" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$text" /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifact-db.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<database> + <!-- This Section configures the Settings for connecting to the + Artifact-Database instance. e.g. SQLite --> + <user>SA</user> + <password></password> + <!-- For use with a postgresql database use the appropriate driver--> + <!--driver>org.postgresql.Driver</driver--> + <url>jdbc:h2:${artifacts.config.dir}/../artifactdb/artifacts.db</url> +</database>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/annotation.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="annotation"> + <states> + <state id="state.annotation.river" + description="state.annotation.river" + state="de.intevation.flys.artifacts.states.AnnotationRiverState"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/chart.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="new_chart"> + <states> + <state id="state.chart.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect"> + <data name="river" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.chart.river"/> + <to state="state.chart.type"/> + </transition> + + <state id="state.chart.type" description="state.chart.type" state="de.intevation.flys.artifacts.ChartArtifact$ChartState"> + <data name="chart_type" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.type"/> + <to state="state.chart.w_differences"/> + <condition data="chart_type" value="chart.new.w_differences" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.type"/> + <to state="state.chart.km"/> + <condition data="chart_type" value="chart.new.durationcurve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.type"/> + <to state="state.chart.km"/> + <condition data="chart_type" value="chart.new.computeddischargecurve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.type"/> + <to state="state.chart.crosssection"/> + <condition data="chart_type" value="chart.new.crosssection" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.type"/> + <to state="state.chart.longitudinal_section"/> + <condition data="chart_type" value="chart.new.longitudinal_section" operator="equal"/> + </transition> + + <state id="state.chart.km" description="state.chart.km" state="de.intevation.flys.artifacts.states.LocationSelect"> + <data name="ld_locations" type="Double[]"/> + </state> + + <state id="state.chart.w_differences" description="state.chart.w_differences" state="de.intevation.flys.artifacts.states.WDifferencesState"> + <outputmodes> + <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart"> + <facets> + <facet name="empty.facet" description="Empty"/> + <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="w_differences" description="facet.w_differences"/> + <facet name="other.wkms" description="facet.other.wkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.chart.longitudinal_section" description="state.chart.logitudinal_section" state="de.intevation.flys.artifacts.states.DischargeLongitudinalSection"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="empty.facet" decription= "Empty"/> + <facet name="discharge_longitudinal_section.w"/> + <facet name="discharge_longitudinal_section.q"/> + <facet name="discharge_longitudinal_section.c"/> + <facet name="other.wqkms"/> + <facet name="other.wkms"/> + <facet name="heightmarks_points"/> + <facet name="longitudinal_section.area" description="an area"/> + <facet name="longitudinal_section.annotations"/> + <facet name="longitudinal_section.w"/> + <facet name="longitudinal_section.manualpoints"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.chart.crosssection" description="state.chart.crosssection" state="de.intevation.flys.artifacts.states.WaterlevelState"> + <outputmodes> + <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart"> + <facets> + <facet name="empty.facet" description="Empty"/> + <facet name="cross_section_water_line" description="facet.cross_section_water_line"/> + <facet name="cross_section" description="facet.cross_section"/> + <facet name="area" description="an area"/> + <facet name="cross_section.area" description="an area"/> + <facet name="cross_section.manualpoints" description="points"/> + <facet name="hyk" description="hyks"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.km"/> + <to state="state.chart.computeddischargecurve"/> + <condition data="chart_type" value="chart.new.computeddischargecurve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.chart.km"/> + <to state="state.chart.durationcurve"/> + <condition data="chart_type" value="chart.new.durationcurve" operator="equal"/> + </transition> + + <state id="state.chart.computeddischargecurve" description="state.chart.computeddischargecurve" state="de.intevation.flys.artifacts.states.ComputedDischargeCurveState"> + <outputmodes> + <outputmode name="computed_discharge_curve" description="output.computed_discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="empty.facet" description="Empty"/> + <facet name="computed_discharge_curve.manualpoints"/> + <facet name="computed_discharge_curve.q" description="facet.computed_discharge_curve.q"/> + <facet name="computed_discharge_curve.mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/> + <facet name="computed_discharge_curve.mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="other.wkms.interpol" description="Height over km, like flood protections."/> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.chart.durationcurve" description="state.chart.durationcurve" state="de.intevation.flys.artifacts.states.DurationCurveState"> + <outputmodes> + <outputmode name="duration_curve" description="output.duration_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="empty.facet" description="Empty"/> + <facet name="duration_curve.manualpoints"/> + <facet name="duration_curve.w" description="facet.duration_curve.w"/> + <facet name="duration_curve.q" description="facet.duration_curve.q"/> + <facet name="computed_discharge_curve.mainvalues.q" description="Q Main Values"/> + <facet name="computed_discharge_curve.mainvalues.w" description="W Main Values"/> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/fixanalysis.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="fixanalysis"> + <states> + <state id="state.fix.river" description="state.fix.river" + state="de.intevation.flys.artifacts.states.RiverSelect"> + <data name="river" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.river"/> + <to state="state.fix.calculation.mode"/> + </transition> + + <state id="state.fix.calculation.mode" + description="state.fix.calcuation.mode" + state="de.intevation.flys.artifacts.states.fixation.FixationSelect"> + <data name="calculation.mode" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.calculation.mode"/> + <to state="state.fix.location"/> + </transition> + + <state id="state.fix.location" description="state.fix.location" + state="de.intevation.flys.artifacts.states.fixation.LocationSelect"> + <data name="from" type="Double"/> + <data name="to" type="Double"/> + <data name="step" type="Double"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.location"/> + <to state="state.fix.period"/> + </transition> + + <state id="state.fix.period" description="state.fix.period" + state="de.intevation.flys.artifacts.states.fixation.FixationPeriod"> + <data name="start" type="Long"/> + <data name="end" type="Long"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.period"/> + <to state="state.fix.gaugerange"/> + </transition> + + <state id="state.fix.gaugerange" description="state.fix.gaugerange" + state="de.intevation.flys.artifacts.states.fixation.GaugeRange"> + <data name="q1" type="Integer"/> + <data name="q2" type="Integer"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.gaugerange"/> + <to state="state.fix.eventselect"/> + </transition> + + <state id="state.fix.eventselect" description="state.fix.eventselect" + state="de.intevation.flys.artifacts.states.fixation.EventSelect"> + <data name="events" type="intarray"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.fix.eventselect"/> + <to state="state.fix.analysis.referenceperiod"/> + <condition data="calculation.mode" value="calculation.analysis" + operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.fix.eventselect"/> + <to state="state.fix.vollmer.function"/> + <condition data="calculation.mode" value="calculation.vollmer" + operator="equal"/> + </transition> + + <state id="state.fix.analysis.referenceperiod" + description="state.fix.analysis.referenceperiod" + state="de.intevation.flys.artifacts.states.fixation.ReferencePeriod"> + <data name="ref_start" type="Long"/> + <data name="ref_end" type="Long"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.analysis.referenceperiod"/> + <to state="state.fix.analysis.analysisperiods"/> + </transition> + + <state id="state.fix.analysis.analysisperiods" + description="state.fix.analysis.analysisperiods" + state="de.intevation.flys.artifacts.states.fixation.AnalysisPeriods"> + <data name="ana_data" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.analysis.analysisperiods"/> + <to state="state.fix.analysis.function"/> + </transition> + + <state id="state.fix.analysis.function" + description="state.fix.analysis.function" + state="de.intevation.flys.artifacts.states.fixation.FunctionSelect"> + <data name="function" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.analysis.function"/> + <to state="state.fix.analysis.preprocessing"/> + </transition> + + <state id="state.fix.analysis.preprocessing" + description="state.fix.analysis.preprocessing" + state="de.intevation.flys.artifacts.states.fixation.PreprocessingSelect"> + <data name="preprocessing" type="Boolean"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.analysis.preprocessing"/> + <to state="state.fix.analysis.compute"/> + </transition> + + <state id="state.fix.analysis.compute" + description="state.fix.analysis.compute" + state="de.intevation.flys.artifacts.states.fixation.FixAnalysisCompute"> + <outputmodes> + <outputmode name="fix_deltawt_export" description="output.fix_deltawt_export" mine-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.fix_deltawt.csv" /> + </facets> + </outputmode> + <outputmode name="fix_parameters_export" description="output.fix_parameters_export" mine-type="text/plain" type="export"> + <facets> + <facet name="fix_parameters" description="facet.fix_parameters.csv" /> + </facets> + </outputmode> + <outputmode name="fix_wq_curve_at_export" description="output.fix_wq_curve_at_export" mime-type="text/plain" type="export"> + <facets> + <facet name="at" description="facet.fix_wq_curve_export.at"/> + </facets> + </outputmode> + <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mine-type="image/png" type="chart"> + <facets> + <facet name="fix_sector_average_wq_0" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_1" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_2" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_3" description="Average values for Ws in Q sectors."/> + <facet name="fix_analysis_events_wq" description="Raw event values used in the calculation"/> + <facet name="fix_reference_events_wq" description="Raw event values used in the calculation"/> + <facet name="fix_wq_curve" description="WQ curve"/> + <facet name="qsectors" description="qsectors."/> + <facet name="fix_outlier" description="The outliers"/> + <facet name="other.wqkms.q" description="W-Type of data" /> + <facet name="other.wqkms.w" description="W-Type of data" /> + <facet name="other.wkms" description="facet.other.wqkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + <facet name="fix_wq_curve.manualpoints" description="Manual points"/> + </facets> + </outputmode> + <outputmode name="fix_deltawt_curve" description="output.fix_deltawt_curve" mine-type="image/png" type="chart"> + <facets> + <facet name="fix_sector_average_dwt_0" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_dwt_1" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_dwt_2" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_dwt_3" description="Average values for Ws in Q sectors."/> + <facet name="fix_analysis_events_dwt" description="Raw event values used in the calculation"/> + <facet name="fix_reference_events_dwt" description="Raw event values used in the calculation"/> + <facet name="fix_analysis_periods_dwt" description="Dateranges of analysis periods."/> + <facet name="fix_deviation_dwt" description="The standard variance"/> + <facet name="fix_deltawt_curve.manualpoints" description="Manual points"/> + </facets> + </outputmode> + <outputmode name="fix_longitudinal_section_curve" description="output.fix_longitudinal_section_curve" mine-type="image/png" type="chart"> + <facets> + <facet name="fix_sector_average_ls_0" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_1" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_2" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_3" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_deviation_0" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_deviation_1" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_deviation_2" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_ls_deviation_3" description="Average values for Ws in Q sectors."/> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/> + <facet name="fix_deviation_ls" description="The standard variance"/> + <facet name="fix_analysis_events_ls" description="Average values for Ws in Q sectors."/> + <facet name="fix_reference_events_ls" description="Average values for Ws in Q sectors."/> + <facet name="fix_longitudinal_section_curve.manualpoints" description="Manual points"/> + </facets> + </outputmode> + <outputmode name="fix_derivate_curve" description="output.fix_derivate_curve" mine-type="image/png" type="chart"> + <facets> + <facet name="fix_derivate" description="Derivate curve"/> + <facet name="fix_derivate_curve.manualpoints" description="Manual points"/> + </facets> + </outputmode> + <outputmode name="fix_report" description="output.fix_report.report" mime-type="text/plain" type="report"> + <facets> + <facet name="report" description="facet.fix.report" /> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.fix.vollmer.function" + description="state.fix.vollmer.function" + state="de.intevation.flys.artifacts.states.fixation.FunctionSelect"> + <data name="function" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.vollmer.function"/> + <to state="state.fix.vollmer.preprocessing"/> + </transition> + + <state id="state.fix.vollmer.preprocessing" + description="state.fix.vollmer.preprocessing" + state="de.intevation.flys.artifacts.states.fixation.PreprocessingSelect"> + <data name="preprocessing" type="Boolean"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.vollmer.preprocessing"/> + <to state="state.fix.vollmer.qs"/> + </transition> + + <state id="state.fix.vollmer.qs" description="state.fix.vollmer.qs" + state="de.intevation.flys.artifacts.states.WQAdapted"> + <data name="wq_isq" type="String" /> + <data name="wq_values" type="WQTriple" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.fix.vollmer.qs"/> + <to state="state.fix.vollmer.compute"/> + </transition> + + <state id="state.fix.vollmer.compute" + description="state.fix.vollmer.compute" + state="de.intevation.flys.artifacts.states.fixation.FixRealizingCompute"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/> + <facet name="w_differences" description="facet.w_differences"/> + <facet name="other.wkms" description="facet.other.wkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="w_differences.manualpoints" description="Manuelle Punkte"/> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/> + </facets> + </outputmode> + <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mine-type="image/png" type="chart"> + <facets> + <facet name="fix_sector_average_wq_0" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_1" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_2" description="Average values for Ws in Q sectors."/> + <facet name="fix_sector_average_wq_3" description="Average values for Ws in Q sectors."/> + <facet name="fix_analysis_events_wq" description="Raw event values used in the calculation"/> + <facet name="fix_reference_events_wq" description="Raw event values used in the calculation"/> + <facet name="fix_wq_curve" description="WQ curve"/> + <facet name="fix_outlier" description="The outliers"/> + <facet name="qsectors" description="qsectors."/> + <facet name="other.wqkms.q" description="W-Type of data" /> + <facet name="other.wqkms.w" description="W-Type of data" /> + <facet name="other.wkms" description="facet.other.wqkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + </facets> + </outputmode> + <outputmode name="fix_waterlevel_export" description="output.fix_waterlevel_export" mine-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.waterlevel_export.csv" /> + <facet name="wst" description="facet.waterlevel_export.wst" /> + <facet name="pdf" description="facet.waterlevel_export.pdf" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/gaugedischarge.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="gaugedischarge"> + <states> + <state id="state.gaugedischarge.init" + description="state.gaugedischarge.init" + state="de.intevation.flys.artifacts.states.GaugeDischargeState"> + <outputmodes> + <outputmode name="computed_discharge_curve" description="computed_discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/hyk.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="hyk"> + <states> + <state id="state.hyk.static" + description="state.hyk.static" + state="de.intevation.flys.artifacts.states.StaticHYKState"> + <outputmodes> + <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart"> + <facets> + <facet name="hyk" description="hyk data" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/manualpoints.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="manualpoints"> + <states> + <state id="state.manualpoints.static" + description="state.manualpoints.static" + state="de.intevation.flys.artifacts.states.ManualPointsSingleState"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.manualpoints" description="Points provided by user." /> + <facet name="discharge_longitudinal_section.manualpoints" description="Points provided by user." /> + <facet name="discharge_curve.manualpoints" description="Points provided by user." /> + <facet name="w_differences.manualpoints" description="Points provided by user." /> + <facet name="duration_curve.manualpoints" description="Points provided by user." /> + <facet name="computed_discharge_curve.manualpoints" description="Points provided by user." /> + <facet name="cross_section.manualpoints" description="Points provided by user." /> + <facet name="reference_curve.manualpoints" description="User-provided points *yawn*"/> + <facet name="reference_curve_normalized.manualpoints" description="points"/> + <facet name="historical_discharge.manualpoints" description="Points provided by user." /> + <facet name="cross_section.manualline" description="Lines provided by user." /> + <facet name="fix_wq_curve.manualpoints" description="Points provided by user." /> + <facet name="fix_deltawt_curve.manualpoints" description="Points provided by user." /> + <facet name="fix_longitudinal_section_curve.manualpoints" description="Points provided by user." /> + <facet name="fix_derivate_curve.manualpoints" description="Points provided by user." /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/map.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="new_map"> + <states> + <state id="state.map.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect"> + <data name="river" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.map.river"/> + <to state="state.map.new"/> + </transition> + + <state id="state.map.new" description="state.map.new" state="de.intevation.flys.artifacts.MapArtifact$MapState"> + <outputmodes> + <outputmode name="map" description="output.uesk.map.description" type="map"> + <facets> + <facet name="floodmap.wsplgen"/> + <facet name="floodmap.barriers"/> + <facet name="floodmap.riveraxis"/> + <facet name="floodmap.wmsbackground"/> + <facet name="floodmap.kms"/> + <facet name="floodmap.qps"/> + <facet name="floodmap.hws"/> + <facet name="floodmap.hydr_boundaries"/> + <facet name="floodmap.hydr_boundaries_poly"/> + <facet name="floodmap.catchment"/> + <facet name="floodmap.floodplain"/> + <facet name="floodmap.lines"/> + <facet name="floodmap.buildings"/> + <facet name="floodmap.fixpoints"/> + <facet name="floodmap.floodmaps"/> + <facet name="floodmap.gauge_location"/> + <facet name="floodmap.externalwms"/> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/minfo.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,303 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="minfo"> + + <states> + <state id="state.minfo.river" description="state.minfo.river" state="de.intevation.flys.artifacts.states.RiverSelect" helpText="help.index"> + <data name="river" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.river"/> + <to state="state.minfo.calculation_mode"/> + </transition> + + <state id="state.minfo.calculation_mode" description="state.minfo.calculation_mode" state="de.intevation.flys.artifacts.states.CalculationSelectMinfo" helpText="help.minfo"> + <data name="calculation_mode" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.calculation_mode"/> + <to state="state.minfo.distance_only"/> + <condition data="calculation_mode" value="calc.flow.velocity" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.calculation_mode"/> + <to state="state.minfo.distance_only"/> + <condition data="calculation_mode" value="calc.bed.middle" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.calculation_mode"/> + <to state="state.minfo.sq.location"/> + <condition data="calculation_mode" value="calc.sq.relation" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.calculation_mode"/> + <to state="state.minfo.bed.year_epoch"/> + <condition data="calculation_mode" value="calc.bed.diff" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.calculation_mode"/> + <to state="state.minfo.bed.location"/> + <condition data="calculation_mode" value="calc.bed.quality" operator="equal"/> + </transition> + + <state id="state.minfo.distance_only" description="state.minfo.distance_only" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.minfo.distance"> + <data name="ld_from" type="Double" /> + <data name="ld_to" type="Double" /> + </state> + + <state id="state.minfo.bed.year_epoch" description="state.minfo.bed.year_epoch" state="de.intevation.flys.artifacts.states.minfo.YearEpochSelect" helpText="help.minfo.year_epoch"> + <data name="ye_select" type="String" /> + </state> + + <state id="state.minfo.sq.location" description="state.minfo.sq.location" state="de.intevation.flys.artifacts.states.LocationSelect" helpText="help.minfo.sq.loaction"> + <data name="ld_locations" type="double"/> + </state> + + <state id="state.minfo.bed.location" description="state.minfo.bed.location" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.minfo.bed.loaction"> + <data name="ld_from" type="Double" /> + <data name="ld_to" type="Double" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.distance_only"/> + <to state="state.minfo.dischargestate"/> + <condition data="calculation_mode" value="calc.flow.velocity" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.minfo.distance_only"/> + <to state="state.minfo.soundings"/> + <condition data="calculation_mode" value="calc.bed.middle" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.sq.location"/> + <to state="state.minfo.sq.period"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.bed.year_epoch"/> + <to state="state.minfo.bed.difference_select"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.bed.location"/> + <to state="state.minfo.bed.periods"/> + </transition> + + <state id="state.minfo.dischargestate" description="state.minfo.dischargestate" state="de.intevation.flys.artifacts.states.DischargeState" helpText="help.minfo.dischargestate"> + <data name="total_channel" type="intoptions"/> + <data name="main_channel" type="intoptions"/> + </state> + + <state id="state.minfo.soundings" description="state.minfo.soundingsstate" state="de.intevation.flys.artifacts.states.SoundingsSelect" helpText="help.minfo.soundingsstate"> + <data name="soundings" type="options"/> + </state> + + <state id="state.minfo.sq.period" description="state.minfo.sq.period" state="de.intevation.flys.artifacts.states.sq.SQPeriodSelect"> + <data name="start" type="Long"/> + <data name="end" type="Long"/> + </state> + + <state id="state.minfo.bed.difference_select" description="state.minfo.bed.difference_select" state="de.intevation.flys.artifacts.states.minfo.DifferenceSelect" helpText="help.minfo.diff_select"> + <data name="diffids" type="String" /> + </state> + + <state id="state.minfo.bed.periods" description="state.minfo.bed.periods" state="de.intevation.flys.artifacts.states.minfo.BedQualityPeriodsSelect"> + <data name="periods" type="String"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.dischargestate"/> + <to state="state.minfo.flow_velocity"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.soundings"/> + <to state="state.minfo.bedheight_middle"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.sq.period"/> + <to state="state.minfo.sq.outliers"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.bed.difference_select"/> + <to state="state.minfo.bed.differences"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.bed.periods"/> + <to state="state.minfo.bed.char_diameter"/> + </transition> + + <state id="state.minfo.flow_velocity" description="state.minfo.flow_velocity" state="de.intevation.flys.artifacts.states.FlowVelocityState" helpText="help.minfo.flowvelocity"> + <outputmodes> + <outputmode name="flow_velocity" description="output.flow_velocity" mime-type="image/png" type="chart"> + <facets> + <facet name="flow_velocity.totalchannel" description="A facet for total channels"/> + <facet name="flow_velocity.mainchannel" description="A facet for main channels"/> + <facet name="flow_velocity.tau" description="A facet for tau"/> + </facets> + </outputmode> + <outputmode name="flow_velocity_export" description="output.flow_velocity_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.flow_velocity_export.csv" /> + <!-- + <facet name="pdf" description="facet.historical_discharge.pdf" /> + --> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.minfo.bedheight_middle" description="state.minfo.bedheight_middle" state="de.intevation.flys.artifacts.states.MiddleBedHeight" helpText="help.minfo.bedheight_middle"> + <outputmodes> + <outputmode name="bedheight_middle" description="output.bedheight_middle" mime-type="image/png" type="chart"> + <facets> + <facet name="bedheight_middle.single" description="A facet for total channels"/> + <facet name="bedheight_middle.epoch" description="A facet for total channels"/> + </facets> + </outputmode> + <outputmode name="bedheight_middle_export" description="output.bedheight_middle_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.bedheight_middle_export.csv" /> + <!-- + <facet name="pdf" description="facet.historical_discharge.pdf" /> + --> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.minfo.sq.outliers" description="state.minfo.sq.outliers" state="de.intevation.flys.artifacts.states.OutliersInput" helpText="help.minfo.sq.outliers"> + <data name="outliers" type="Double"/> + </state> + + <state id="state.minfo.bed.differences" description="state.minfo.bed.differences" state="de.intevation.flys.artifacts.states.minfo.DifferencesState" helpText="help.minfo.bed.differences"> + <outputmodes> + <outputmode name="absolute_height" description="output.absolute_height" mime-type="image/png" type="chart"> + <facets> + </facets> + </outputmode> + <outputmode name="difference_year" description="output.difference_year" mime-type="img/png" type="chart"> + <facets> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.minfo.bed.char_diameter" description="state.minfo.bed.char_diameter" state="de.intevation.flys.artifacts.states.minfo.CharDiameter"> + <data name="bed_diameter" type="options"/> + <data name="load_diameter" type="options"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.sq.outliers"/> + <to state="state.minfo.sq.relation"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.minfo.bed.char_diameter"/> + <to state="state.minfo.bed.bed_quality"/> + </transition> + + <state id="state.minfo.sq.relation" description="state.minfo.sq.relation" state="de.intevation.flys.artifacts.states.SQRelation"> + <outputmodes> + <outputmode name="sq_relation_a" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_a_measurement" description="A facet for sq measurements"/> + <facet name="sq_a_outlier" description="A facet fo sq outliers"/> + <facet name="sq_a_curve" description="A facet for sq curve"/> + <facet name="sq_a_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_a_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_relation_b" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_b_measurement" description="A facet for sq measurements"/> + <facet name="sq_b_outlier" description="A facet fo sq outliers"/> + <facet name="sq_b_curve" description="A facet for sq curve"/> + <facet name="sq_b_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_b_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_relation_c" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_c_measurement" description="A facet for sq measurements"/> + <facet name="sq_c_outlier" description="A facet fo sq outliers"/> + <facet name="sq_c_curve" description="A facet for sq curve"/> + <facet name="sq_c_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_c_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_relation_d" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_d_measurement" description="A facet for sq measurements"/> + <facet name="sq_d_outlier" description="A facet fo sq outliers"/> + <facet name="sq_d_curve" description="A facet for sq curve"/> + <facet name="sq_d_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_d_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_relation_e" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_e_measurement" description="A facet for sq measurements"/> + <facet name="sq_e_outlier" description="A facet fo sq outliers"/> + <facet name="sq_e_curve" description="A facet for sq curve"/> + <facet name="sq_e_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_e_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_relation_f" description="output.sq_relation" type="chart"> + <facets> + <facet name="sq_f_measurement" description="A facet for sq measurements"/> + <facet name="sq_f_outlier" description="A facet fo sq outliers"/> + <facet name="sq_f_curve" description="A facet for sq curve"/> + <facet name="sq_f_outlier_curve" description="A facet for sq outlier curve"/> + <facet name="sq_f_outlier_measurement" description="A facet for sq outlier measurement"/> + </facets> + </outputmode> + <outputmode name="sq_overview" description="output.sq_overview" type="overview"> + <facets> + <facet name="sq_chart_overview" description="A facet for sq chart overview"/> + </facets> + </outputmode> + <outputmode name="sq_relation_export" description="output.sq_relation_export" type="export"> + <facets> + <facet name="csv" description="facet.sq_export.csv" /> + <facet name="pdf" description="facet.sq_export.pdf" /> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.minfo.bed.bed_quality" description="state.minfo.bed.bed_quality" state="de.intevation.flys.artifacts.states.minfo.BedQualityState" helpText="help.minfo.bed.bed_quality"> + <outputmodes> + <outputmode name="bed_longitudinal_section" description="output.bed_longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="bed_longitudinal_section.porosity_toplayer"/> + <facet name="bed_longitudinal_section.porosity_sublayer"/> + <facet name="bed_longitudinal_section.sediment_density_toplayer"/> + <facet name="bed_longitudinal_section.sediment_density_sublayer"/> + <facet name="bed_longitudinal_section.bed_diameter_toplayer"/> + <facet name="bed_longitudinal_section.bed_diameter_sublayer"/> + <facet name="bed_longitudinal_section.bedload_diameter"/> + </facets> + </outputmode> + <outputmode name="bed_quality_export" description="output.bed_quality_export" type="export"> + <facets> + <facet name="csv" description="facet.bed_quality_export.csv" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> + +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/qsector.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="qsector"> + <states> + <state id="state.qsector.static" + description="state.qsector.static" + state="de.intevation.flys.artifacts.states.QSectorSingleState"> + <outputmodes> + <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="qsectors" description="qsectors."/> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/staticwqkms.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="staticwqkms"> + <states> + <state id="state.staticwqkms.static" + description="state.staticwqkms.state" + state="de.intevation.flys.artifacts.states.StaticWQKmsState"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="other.wqkms.w" description="W-type data" /> + <facet name="other.wqkms.q" description="Q-type data" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/waterlevel.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="waterlevel"> + <states> + <state id="state.waterlevel.done" + description="state.waterlevel.done" + state="de.intevation.flys.artifacts.states.WaterlevelInfoState"> + <outputmodes> + <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w" /> + <facet name="longitudinal_section.q" description="facet.longitudinal_section.q" /> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/winfo.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,561 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="winfo"> + <states> + + <state id="state.winfo.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect" helpText="help.index"> + <data name="river" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <from state="state.winfo.river"/> + <to state="state.winfo.calculation_mode"/> + </transition> + + <state id="state.winfo.calculation_mode" description="state.winfo.calculation_mode" state="de.intevation.flys.artifacts.states.CalculationSelect" helpText="help.winfo"> + <data name="calculation_mode" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.location_distance"/> + <condition data="calculation_mode" value="calc.surface.curve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.distance_only"/> + <condition data="calculation_mode" value="calc.flood.map" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.location"/> + <condition data="calculation_mode" value="calc.discharge.curve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.location"/> + <condition data="calculation_mode" value="calc.duration.curve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.distance"/> + <condition data="calculation_mode" value="calc.discharge.longitudinal.section" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.waterlevel_pair_select"/> + <condition data="calculation_mode" value="calc.w.differences" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.historicalq.reference_gauge"/> + <condition data="calculation_mode" value="calc.historical.discharge.curve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.waterlevel_pair_select"/> + <to state="state.winfo.w_differences"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.calculation_mode"/> + <to state="state.winfo.reference.curve.input.start"/> + <condition data="calculation_mode" value="calc.reference.curve" operator="equal"/> + </transition> + + <state id="state.winfo.location" description="state.winfo.location" state="de.intevation.flys.artifacts.states.LocationSelect" helpText="help.winfo.duration.locations"> + <data name="ld_locations" type="Double[]" /> + + <!-- + <outputmodes> + <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/> + <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/> + <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + </facets> + </outputmode> + </outputmodes> + --> + </state> + + <state id="state.winfo.distance_only" description="state.winfo.distance_only" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.winfo.uesk.distance"> + <data name="ld_from" type="Double" /> + <data name="ld_to" type="Double" /> + </state> + + <state id="state.winfo.distance" description="state.winfo.distance" state="de.intevation.flys.artifacts.states.DistanceSelect" helpText="help.winfo.discharge.longitudinal.distance"> + <data name="ld_from" type="Double" /> + <data name="ld_to" type="Double" /> + <data name="ld_step" type="Double" /> + + <!-- + <outputmodes> + <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/> + <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/> + <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + </facets> + </outputmode> + </outputmodes> + --> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.distance_only"/> + <to state="state.winfo.uesk.wsp"/> + </transition> + + <state id="state.winfo.location_distance" description="state.winfo.location_distance" state="de.intevation.flys.artifacts.states.LocationDistanceSelect" helpText="help.winfo.wsp.location_distance"> + <data name="ld_mode" type="String" /> + <data name="ld_locations" type="Double[]" /> + <data name="ld_from" type="Double" /> + <data name="ld_to" type="Double" /> + <data name="ld_step" type="Double" /> + + <!-- + <outputmodes> + <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/> + <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/> + <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + </facets> + </outputmode> + </outputmodes> + --> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.distance"/> + <to state="state.winfo.wq_adapted"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.location_distance"/> + <to state="state.winfo.wq"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.location"/> + <to state="state.winfo.durationcurve"/> + <condition data="calculation_mode" value="calc.duration.curve" operator="equal"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition"> + <from state="state.winfo.location"/> + <to state="state.winfo.computeddischargecurve"/> + <condition data="calculation_mode" value="calc.discharge.curve" operator="equal"/> + </transition> + + <state id="state.winfo.wq" description="state.winfo.wq" state="de.intevation.flys.artifacts.states.WQSelect" helpText="help.winfo.wsp.wq"> + <data name="wq_isq" type="Boolean" /> + <data name="wq_isfree" type="Boolean" /> + <data name="wq_isrange" type="Boolean" /> + <data name="wq_from" type="Double" /> + <data name="wq_to" type="Double" /> + <data name="wq_step" type="Double" /> + <data name="wq_single" type="Double[]" /> + </state> + + <state id="state.winfo.wq_adapted" description="state.winfo.wq_adapted" + state="de.intevation.flys.artifacts.states.WQAdapted" helpText="help.winfo.discharge.longitudinal.wq"> + <!-- TODO Add data objects --> + <data name="wq_isq" type="String" /> + <data name="wq_values" type="WQTriple" /> + </state> + + <state id="state.winfo.waterlevel_pair_select" description="state.winfo.waterlevel_pair_select" state="de.intevation.flys.artifacts.states.WaterlevelPairSelectState" helpText="help.winfo.diff.diffs"> + <data name="diffids" type="String" /> + </state> + + <state id="state.winfo.reference.curve.input.start" description="state.winfo.reference.curve.input (start)" state="de.intevation.flys.artifacts.states.EnterLocationState" helpText="help.winfo.reference.curve.start"> + <data name="reference_startpoint" type="Double[]"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.reference.curve.input.start"/> + <to state="state.winfo.reference.curve.input.end"/> + </transition> + + <state id="state.winfo.reference.curve.input.end" description="state.winfo.reference.curve.input (end)" state="de.intevation.flys.artifacts.states.EnterMultipleLocationsState" helpText="help.winfo.reference.curve.end"> + <data name="reference_endpoint" type="Double[]"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.reference.curve.input.end"/> + <to state="state.winfo.reference.curve"/> + </transition> + + <state id="state.winfo.reference.curve" description="state.winfo.reference.curve" state="de.intevation.flys.artifacts.states.ReferenceCurveState" helpText=""> + <outputmodes> + <outputmode name="reference_curve_normalized" mime-type="image/png" type="chart"> + <facets> + <facet name="reference_curve_normalized" description="A normalized reference curve!"/> + <facet name="reference_curve_normalized.manualpoints" description="points"/> + </facets> + </outputmode> + <outputmode name="reference_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="reference_curve" description="A ... reference curve!"/> + <facet name="reference_curve.manualpoints" description="points"/> + <facet name="relativepoint" description="Points at curve"/> + <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + </facets> + </outputmode> + <outputmode name="reference_curve_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.reference_curve_export.csv" /> + <facet name="pdf" description="facet.reference_curve_export.pdf" /> + </facets> + </outputmode> + <outputmode name="reference_curve_report" description="output.reference_curve_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.reference_curve_export.report" /> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.winfo.w_differences" description="state.winfo.w_differences" state="de.intevation.flys.artifacts.states.WDifferencesState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + + <outputmodes> + <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="w_differences" description="facet.w_differences"/> + <facet name="other.wkms" description="facet.other.wkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="w_differences.manualpoints" description="Manuelle Punkte"/> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/> + </facets> + </outputmode> + <outputmode name="w_differences_export" description="output.w_differences.export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.w_differences.csv" /> + <facet name="pdf" description="facet.w_differences.pdf" /> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.winfo.durationcurve" description="state.winfo.durationcurve" state="de.intevation.flys.artifacts.states.DurationCurveState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="duration_curve" description="output.duration_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="duration_curve.w" description="facet.duration_curve.w"/> + <facet name="duration_curve.q" description="facet.duration_curve.q"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="duration_curve.mainvalues.q" description="Q Main Values at optional second axis"/> + <facet name="computed_discharge_curve.mainvalues.w" description="W Main Values"/> + <facet name="duration_curve.manualpoints" description="Manuelle Punkte"/> + <facet name="relativepoint" description="Points at curve"/> + </facets> + </outputmode> + <outputmode name="durationcurve_export" description="output.durationcurve_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.durationcurve_export.csv" /> + <facet name="pdf" description="facet.durationcurve_export.pdf" /> + </facets> + </outputmode> + <outputmode name="durationcurve_report" description="output.durationcurve_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.durationcurve_export.report" /> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.winfo.computeddischargecurve" description="state.winfo.computeddischargecurve" state="de.intevation.flys.artifacts.states.ComputedDischargeCurveState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="computed_discharge_curve" description="output.computed_discharge_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="computed_discharge_curve.q" description="facet.computed_discharge_curve.q"/> + <facet name="computed_discharge_curve.mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/> + <facet name="computed_discharge_curve.mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/> + <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/> + <facet name="heightmarks_points" description="facet.other.wqkms"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="other.wq" description="Point-like data like fixations"/> + <facet name="other.wkms" description="Point-like data like fixations"/> + <facet name="other.wkms.interpol" description="Height over km, like flood protections."/> + <facet name="computed_discharge_curve.manualpoints" description="Manuelle Punkte"/> + </facets> + </outputmode> + <outputmode name="computed_dischargecurve_export" description="output.computed_dischargecurve_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.computed_dischargecurve_export.csv" /> + <facet name="pdf" description="facet.computed_dischargecurve_export.pdf" /> + </facets> + </outputmode> + <outputmode name="computed_dischargecurve_report" description="output.computed_dischargecurve_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.computed_dischargecurve_export.report"/> + </facets> + </outputmode> + <outputmode name="computed_dischargecurve_at_export" description="output.computed_dischargecurve_at_export" mime-type="text/plain" type="export"> + <facets> + <facet name="at" description="facet.computed_dischargecurve_export.at"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.wq"/> + <to state="state.winfo.waterlevel"/> + </transition> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.wq_adapted"/> + <to state="state.winfo.discharge_longitudinal_section"/> + </transition> + + <state id="state.winfo.waterlevel" description="state.winfo.waterlevel" state="de.intevation.flys.artifacts.states.WaterlevelState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/> + <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/> + <facet name="w_differences" description="facet.w_differences"/> + <facet name="other.wqkms.w" description="W-Type of data" /> + <facet name="other.wq" description="WQ-Type of data" /> + <facet name="other.wqkms.q" description="Q-Type of data" /> + <facet name="other.wkms" description="facet.other.wkms"/> + <facet name="longitudinal_section.manualpoints" description="Manuelle Punkte"/> + <facet name="other.wqkms" description="facet.other.wqkms"/> + <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/> + <facet name="longitudinal_section.area" description="an area"/> + <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/> + </facets> + </outputmode> + <outputmode name="waterlevel_export" description="output.waterlevel_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.waterlevel_export.csv" /> + <facet name="wst" description="facet.waterlevel_export.wst" /> + <facet name="pdf" description="facet.waterlevel_export.pdf" /> + </facets> + </outputmode> + <outputmode name="waterlevel_report" description="output.waterlevel_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.waterlevel_export.report"/> + </facets> + </outputmode> + <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart"> + <facets> + <facet name="cross_section_water_line" description="facet.cross_section_water_line"/> + <facet name="cross_section" description="facet.cross_section"/> + <facet name="area" description="an area"/> + <facet name="cross_section.area" description="an area"/> + <facet name="cross_section.manualpoints" description="points"/> + <facet name="cross_section.manualline" description="line"/> + <facet name="hyk" description="hyks"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <state id="state.winfo.discharge_longitudinal_section" description="state.winfo.discharge_longitudinal_section" state="de.intevation.flys.artifacts.states.DischargeLongitudinalSection" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="discharge_longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png" type="chart"> + <facets> + <facet name="discharge_longitudinal_section.w"/> + <facet name="discharge_longitudinal_section.q"/> + <facet name="discharge_longitudinal_section.c"/> + <facet name="discharge_longitudinal_section.manualpoints" description="Manuelle Punkte"/> + <facet name="other.wqkms.w"/> + <facet name="other.wq"/> + <facet name="other.wqkms.q"/> + <facet name="other.wqkms"/> + <facet name="other.wkms"/> + <facet name="heightmarks_points"/> + <facet name="longitudinal_section.annotations"/> + <facet name="longitudinal_section.w"/> + <facet name="longitudinal_section.q"/> + </facets> + </outputmode> + <outputmode name="discharge_longitudinal_section_export" description="output.discharge_longitudinal_section_export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.discharge_longitudinal_section_export.csv" /> + <facet name="wst" description="facet.discharge_longitudinal_section_export.wst" /> + </facets> + </outputmode> + <outputmode name="discharge_longitudinal_section_report" description="output.discharge_longitudinal_section_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.discharge_longitudinal_section_export.report"/> + </facets> + </outputmode> + <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart"> + <facets> + <facet name="cross_section_water_line" description="facet.cross_section_water_line"/> + <facet name="cross_section" description="facet.cross_section"/> + <facet name="area" description="an area"/> + <facet name="cross_section.area" description="an area"/> + <facet name="cross_section.manualpoints" description="points"/> + <facet name="cross_section.manualline" description="line"/> + <facet name="hyk" description="hyks"/> + </facets> + </outputmode> + </outputmodes> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.waterlevel"/> + <to state="state.winfo.uesk.dgm"/> + </transition> + + <state id="state.winfo.uesk.wsp" description="state.winfo.uesk.wsp" state="de.intevation.flys.artifacts.states.WaterlevelSelectState" helpText="help.winfo.uesk.wsp"> + <data name="wsp" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.wsp"/> + <to state="state.winfo.uesk.dgm"/> + </transition> + + <state id="state.winfo.uesk.dgm" description="state.winfo.uesk.dgm" state="de.intevation.flys.artifacts.states.DGMSelect" helpText="help.winfo.uesk.dem"> + <data name="dgm" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.dgm"/> + <to state="state.winfo.uesk.profiles"/> + </transition> + + <state id="state.winfo.uesk.profiles" description="state.winfo.uesk.profiles" state="de.intevation.flys.artifacts.states.ProfileDistanceSelect" helpText="help.winfo.uesk.profiles"> + <data name="profile_distance" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.profiles"/> + <to state="state.winfo.uesk.floodplain"/> + </transition> + + <state id="state.winfo.uesk.floodplain" description="state.winfo.uesk.floodplain.description" state="de.intevation.flys.artifacts.states.FloodplainChoice" helpText="help.winfo.uesk.floodplain"> + <data name="use_floodplain" type="Boolean" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.floodplain"/> + <to state="state.winfo.uesk.differences"/> + </transition> + + <state id="state.winfo.uesk.differences" description="state.winfo.uesk.differences" state="de.intevation.flys.artifacts.states.WaterlevelGroundDifferences" helpText="help.winfo.uesk.differences"> + <data name="diff_from" type="Double" /> + <data name="diff_to" type="Double" /> + <data name="diff_diff" type="Double" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.differences"/> + <to state="state.winfo.uesk.scenario"/> + </transition> + + <state id="state.winfo.uesk.scenario" description="state.winfo.uesk.scenario" state="de.intevation.flys.artifacts.states.ScenarioSelect" helpText="help.winfo.uesk.scenario"> + <data name="scenario" type="String" /> + <data name="uesk.barriers" type="String" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.uesk.scenario"/> + <to state="state.winfo.uesk.uesk"/> + </transition> + + <state id="state.winfo.uesk.uesk" description="state.winfo.uesk.uesk" state="de.intevation.flys.artifacts.states.FloodMapState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="floodmap" description="output.uesk.map.description" type="map"> + <facets> + <facet name="floodmap.wsplgen"/> + <facet name="floodmap.barriers"/> + <facet name="floodmap.usershape"/> + <facet name="floodmap.riveraxis"/> + <facet name="floodmap.wmsbackground"/> + <facet name="floodmap.kms"/> + <facet name="floodmap.qps"/> + <facet name="floodmap.hws"/> + <facet name="floodmap.hydr_boundaries"/> + <facet name="floodmap.hydr_boundaries_poly"/> + <facet name="floodmap.catchment"/> + <facet name="floodmap.floodplain"/> + <facet name="floodmap.lines"/> + <facet name="floodmap.buildings"/> + <facet name="floodmap.fixpoints"/> + <facet name="floodmap.floodmaps"/> + <facet name="floodmap.gauge_location"/> + <facet name="floodmap.externalwms"/> + </facets> + </outputmode> + <outputmode name="wsplgen_report" description="output.wsplgen_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.wsplgen_export.report"/> + </facets> + </outputmode> + </outputmodes> + </state> + + + <!-- path for historical discharge curves --> + <state id="state.winfo.historicalq.reference_gauge" description="state.winfo.historicalq.reference_gauge" state="de.intevation.flys.artifacts.states.ReferenceGaugeState" helpText="help.winfo.historical.discharge.reference_gauge"> + <data name="reference_gauge" type="Integer" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.historicalq.reference_gauge"/> + <to state="state.winfo.historicalq.timerange"/> + </transition> + + <state id="state.winfo.historicalq.timerange" description="state.winfo.historicalq.timerange" state="de.intevation.flys.artifacts.states.GaugeTimerangeState" helpText="help.winfo.historical.discharge.timerange"> + <data name="year_range" type="longrange"/> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.historicalq.timerange"/> + <to state="state.winfo.historicalq.mode"/> + </transition> + + <state id="state.winfo.historicalq.mode" description="state.winfo.historicalq.mode" state="de.intevation.flys.artifacts.states.HistoricalDischargeState" helpText="help.winfo.historical.discharge.mode"> + <data name="historical_mode" type="intoptions" /> + <data name="historical_values" type="doublearray" /> + </state> + + <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition"> + <from state="state.winfo.historicalq.mode"/> + <to state="state.winfo.historicalq.compute"/> + </transition> + + <state id="state.winfo.historicalq.compute" description="state.winfo.historicalq.compute" state="de.intevation.flys.artifacts.states.HistoricalDischargeComputeState" helpText="https://flys-intern.intevation.de/Flys-3.0"> + <outputmodes> + <outputmode name="historical_discharge" description="output.historical_discharge.description" mime-type="image/png" type="chart"> + <facets> + <facet name="historical_discharge.historicalq"/> + <facet name="historical_discharge.historicalq.diff"/> + <facet name="historical_discharge.manualpoints"/> + </facets> + </outputmode> + <outputmode name="historical_discharge_export" description="output.historical_discharge.export" mime-type="text/plain" type="export"> + <facets> + <facet name="csv" description="facet.historical_discharge.csv" /> + <facet name="pdf" description="facet.historical_discharge.pdf" /> + </facets> + </outputmode> + <outputmode name="historical_discharge_report" description="output.historical_discharge_report" mime-type="text/xml" type="report"> + <facets> + <facet name="report" description="facet.historical_discharge.report"/> + </facets> + </outputmode> + </outputmodes> + </state> + + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/artifacts/wmsbackground.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<artifact name="wmsbackground"> + <states> + <state id="state.wmsbackground.layer" + description="state.wmsbackground.layer.description" + state="de.intevation.flys.artifacts.states.WMSBackgroundState"> + <outputmodes> + <outputmode name="floodmap" description="output.uesk.map.description" type="map"> + <facets> + <facet name="floodmap.wmsbackground"/> + </facets> + </outputmode> + </outputmodes> + </state> + </states> +</artifact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/backend-db.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<backend-database> + <!-- This is the default backend db configuration. --> + <user>flys</user> + <password>flys</password> + <dialect>org.hibernate.dialect.PostgreSQLDialect</dialect> + <driver>org.postgresql.Driver</driver> + <url>jdbc:postgresql://localhost:5432/flys</url> +</backend-database>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/cache.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ehcache> + + <diskStore path="java.io.tmpdir"/> + + <defaultCache + maxElementsInMemory="1000" + eternal="false" + timeToIdleSeconds="120" + timeToLiveSeconds="3600" + overflowToDisk="true" + maxElementsOnDisk="100000" + diskPersistent="false" + diskExpiryThreadIntervalSeconds="120" + memoryStoreEvictionPolicy="LRU" + /> + + <!-- This one is used for the WST value tables --> + + <cache name="wst-value-table" + maxElementsInMemory="20" + maxElementsOnDisk="100" + eternal="false" + timeToIdleSeconds="360" + overflowToDisk="true" + timeToLiveSeconds="14400" + diskPersistent="true" + memoryStoreEvictionPolicy="LRU" + /> + + <cache name="location-provider" + maxElementsInMemory="20" + eternal="false" + diskPersistent="true" + overflowToDisk="true" + timeToIdleSeconds="360" + timeToLiveSeconds="86400" + memoryStoreEvictionPolicy="LFU" + /> + + <!-- This one is used to cache the computed values.--> + <cache name="computed.values" + maxElementsInMemory="200" + eternal="false" + timeToLiveSeconds="172800" + overflowToDisk="true" + diskPersistent="true" + memoryStoreEvictionPolicy="LRU" + /> + + <!-- This one is used to cache the non-computed wst-values.--> + <cache name="wst-value-table-static" + maxElementsInMemory="200" + eternal="false" + timeToLiveSeconds="172800" + overflowToDisk="true" + diskPersistent="true" + memoryStoreEvictionPolicy="LRU" + /> + + <!-- This one is used to cache the non-computed wst-values.--> + <cache name="wst-wq-value-table-static" + maxElementsInMemory="200" + eternal="false" + timeToLiveSeconds="172800" + overflowToDisk="true" + diskPersistent="true" + memoryStoreEvictionPolicy="LRU" + /> + + <!-- This one is used for the SQL statements used by the static datacage --> + <cache name="datacage.db" + maxElementsInMemory="2000" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LFU" + /> + + <!-- This one is used for the cross section next neighbor lookup --> + <cache name="cross-section-kms" + maxElementsInMemory="50" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LRU" + /> + + <!-- This one is used to load chunks of the cross section lines --> + <cache name="fast-cross-section-lines" + maxElementsInMemory="500" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LRU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used to hold the S/Q overviews. --> + <cache name="sq-overviews" + maxElementsInMemory="15" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LFU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used to hold the fixings overviews. --> + <cache name="fixings-overviews" + maxElementsInMemory="15" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LFU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used to hold the data columns of fixings. --> + <cache name="fixings-columns" + maxElementsInMemory="70" + eternal="false" + timeToLiveSeconds="7200" + memoryStoreEvictionPolicy="LFU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used to load single HYK Zones --> + <cache name="hykache" + maxElementsInMemory="500" + eternal="false" + timeToLiveSeconds="14400" + memoryStoreEvictionPolicy="LRU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used to load gauge finders --> + <cache name="gauge-finders" + maxElementsInMemory="15" + eternal="false" + timeToLiveSeconds="14400" + memoryStoreEvictionPolicy="LRU" + overflowToDisk="true" + diskPersistent="true" + /> + + <!-- This one is used for the cross section lookup + Because of lazy fetching and relatively big amount of data, disabled + cache for now. + <cache name="cross_sections" + maxElementsInMemory="50" + eternal="false" + timeToLiveSeconds="86400" + memoryStoreEvictionPolicy="LRU" + /> + --> +</ehcache>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/conf.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,360 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE artifact-database [ + <!ENTITY artifact-db SYSTEM "artifact-db.xml"> + <!ENTITY datacage-db SYSTEM "datacage-db.xml"> + <!ENTITY backend-db SYSTEM "backend-db.xml"> + <!ENTITY seddb-db SYSTEM "seddb-db.xml"> + <!ENTITY rest-server SYSTEM "rest-server.xml"> + <!ENTITY floodmap SYSTEM "floodmap.xml"> +]> +<artifact-database> + <export-secret>YOUR_SECRET</export-secret> + <factories> + <context-factory>de.intevation.flys.artifacts.context.FLYSContextFactory</context-factory> + + <collection-factory + name="DefaultArtifactCollectionFactory" + description="The default artifact collection factory" + ttl="21600000" + artifact-collection="de.intevation.flys.collections.FLYSArtifactCollection">de.intevation.artifactdatabase.DefaultArtifactCollectionFactory</collection-factory> + + <artifact-factories> + <!-- All Artifactfactories which are available in this Database. --> + <artifact-factory name="winfo" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WINFOArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="riveraxis" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.RiverAxisArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="hyk" description="Factory to create an artifact to be used for hyks" + ttl="3600000" + artifact="de.intevation.flys.artifacts.HYKArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="new_map" description="Factory to create an artifact to be used for new map" + ttl="3600000" + artifact="de.intevation.flys.artifacts.MapArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmskmfactory" description="Factory to create an artifact that generates WMS facets for KMs." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSKmArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsqpsfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSQPSArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmshwsfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSHwsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmshydrboundariesfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSHydrBoundaryArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmshydrboundariespolyfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSHydrBoundaryPolyArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmscatchmentfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSCatchmentArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsfloodplainfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks." + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSFloodplainArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmslinefactory" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSLineArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsbuildingsfactory" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSBuildingsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsfixpointsfactory" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSFixpointsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsfloodmapsfactory" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSFloodmapsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsgaugelocationfactory" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSGaugeLocationArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wmsbackground" description="Factory to create an artifact to be used in WINFO" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WMSBackgroundArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="externalwmsfactory" description="Factory to create an artifact to be used in Floodmaps to display external WMS layers" + ttl="3600000" + artifact="de.intevation.flys.artifacts.ExternalWMSArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="annotations" description="Factory to create an artifact to access Annotations for Points at rivers" + ttl="3600000" + artifact="de.intevation.flys.artifacts.AnnotationArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="crosssections" description="Factory to create an artifact to access cross sections" + ttl="3600000" + artifact="de.intevation.flys.artifacts.CrossSectionArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="waterlevel" description="Factory to create an artifact to access waterlevel data" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WaterlevelArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="mainvalue" description="Factory to create an artifact to access Main Values for discharge curve diagrams" + ttl="3600000" + artifact="de.intevation.flys.artifacts.MainValuesArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="staticwkms" description="Factory to create an artifact to access 'other' WKms data" + ttl="3600000" + artifact="de.intevation.flys.artifacts.StaticWKmsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="area" description="Factory to create an artifact to draw (wkms) area data" + ttl="3600000" + artifact="de.intevation.flys.artifacts.AreaArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="staticwqkms" description="Factory to create an artifact to access 'other' WKms data" + ttl="3600000" + artifact="de.intevation.flys.artifacts.StaticWQKmsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="wqinterpol" description="Factory to create an artifact to access 'other' WQ (at km) data" + ttl="3600000" + artifact="de.intevation.flys.artifacts.WQKmsInterpolArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="new_chart" description="Factory to create an artifact to be used for new chart" + ttl="3600000" + artifact="de.intevation.flys.artifacts.ChartArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="manualpoints" description="Factory to create an artifact for storing and editing points added by the user." + ttl="3600000" + artifact="de.intevation.flys.artifacts.ManualPointsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="fixanalysis" description="Factory to create an artifact to be used in fixation analysis." + ttl="3600000" + artifact="de.intevation.flys.artifacts.FixationArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="gaugedischarge" description="Factory to create an artifact to host historical qs." + ttl="3600000" + artifact="de.intevation.flys.artifacts.GaugeDischargeArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="qsectors" description="Factory to create an artifact to host qsectors." + ttl="3600000" + artifact="de.intevation.flys.artifacts.QSectorArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + + <!-- MINFO specific Artifacts --> + <artifact-factory name="minfo" description="Factory to create an artifact to be used in module minfo." + ttl="3600000" + artifact="de.intevation.flys.artifacts.MINFOArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + <artifact-factory name="bedheight" description="Factory to create an artifact used in minfo datacage." + ttl="3600000" + artifact="de.intevation.flys.artifacts.BedHeightsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory> + </artifact-factories> + + <user-factory name="default" description="Factory to create new users">de.intevation.artifactdatabase.DefaultUserFactory</user-factory> + + <service-factories> + <service-factory + name="rivers" + service="de.intevation.flys.artifacts.services.RiverService" + description="This service returns a list of provided rivers by the artifact server.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="distanceinfo" + service="de.intevation.flys.artifacts.services.DistanceInfoService" + description="Returns a list of distances supported by a specific river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="mainvalues" + service="de.intevation.flys.artifacts.services.MainValuesService" + description="Returns the main values of a river's gauge based on a start and end point of the river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="metadata" + service="de.intevation.flys.artifacts.services.MetaDataService" + description="The service provides some introspection into the database content.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="mapinfo" + service="de.intevation.flys.artifacts.services.MapInfoService" + description="The service provides some basic information to create a WMS for a specific river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="cross-section-km" + service="de.intevation.flys.artifacts.services.CrossSectionKMService" + description="The service provides the N next neighbored kms and ids of cross section lines for given cross section id, km and N.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="cache-invalidation" + service="de.intevation.flys.artifacts.services.CacheInvalidationService" + description="The service invalidates caches.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="dischargeinfo" + service="de.intevation.flys.artifacts.services.DischargeInfoService" + description="Returns description, start year and end year of discharges at a specific gauge.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="fixings-overview" + service="de.intevation.flys.artifacts.services.FixingsOverviewService" + description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="fixings-km-chart" + service="de.intevation.flys.artifacts.services.FixingsKMChartService" + description="Returns a chart of fixings of given river and km.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="gaugeinfo" + service="de.intevation.flys.artifacts.services.GaugeInfoService" + description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="fileupload" + service="de.intevation.flys.artifacts.services.FileUploadService" + description="Takes base64 coded files embedded in XML.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="themelisting" + service="de.intevation.flys.artifacts.services.ThemeListingService" + description="Returns a list of Themes filtered by theme name.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="sq-km-chart" + service="de.intevation.flys.artifacts.services.SQKMChartService" + description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="modules" + service="de.intevation.flys.artifacts.services.ModuleService" + description="Returns a list of available modules.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="bed-km-chart" + service="de.intevation.flys.artifacts.services.BedKMChartService" + description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="bedload-km-chart" + service="de.intevation.flys.artifacts.services.BedloadKMChartService" + description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + <service-factory + name="gaugeoverviewinfo" + service="de.intevation.flys.artifacts.services.GaugeOverviewInfoService" + description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory> + </service-factories> + + </factories> + + <lifetime-listeners> + <listener>de.intevation.flys.artifacts.datacage.Datacage</listener> + <listener>de.intevation.flys.wsplgen.SchedulerSetup</listener> + </lifetime-listeners> + + <backend-listeners> + <listener>de.intevation.flys.artifacts.datacage.DatacageBackendListener</listener> + </backend-listeners> + + <callcontext-listener + name="SessionCallContextListener" + description="A CallContext.Listener to open and close Hibernatesessions">de.intevation.flys.artifacts.context.SessionCallContextListener</callcontext-listener> + + <artifacts> + <artifact name="manualpoints" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/manualpoints.xml" /> + <artifact name="winfo" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/winfo.xml" /> + <artifact name="minfo" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/minfo.xml" /> + <artifact name="waterlevel" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/waterlevel.xml" /> + <artifact name="annotation" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/annotation.xml" /> + <artifact name="hyk" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/hyk.xml" /> + <artifact name="wmsbackground" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/wmsbackground.xml" /> + <artifact name="new_map" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/map.xml" /> + <artifact name="new_chart" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/chart.xml" /> + <artifact name="staticwqkms" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/staticwqkms.xml" /> + <artifact name="fixanalysis" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/fixanalysis.xml" /> + <artifact name="gaugedischarge" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/gaugedischarge.xml" /> + <artifact name="qsector" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/qsector.xml" /> + </artifacts> + + <modules> + <module name="winfo" selected="true"/> + <module name="minfo"/> + <module name="new_map"/> + <module name="new_chart"/> + <module name="fixanalysis"/> + </modules> + + <hooks> + <hook + class="de.intevation.flys.artifacts.CollectionMonitor" + applies="post-feed,post-advance,post-describe" + xmlns:xlink="http://www.w3.org/1999/xlink" + xlink:href="${artifacts.config.dir}/output-defaults.xml"> + </hook> + </hooks> + + <output-generators> + <output-generator name="discharge_curve">de.intevation.flys.exports.DischargeCurveGenerator</output-generator> + <output-generator name="discharge_curve_chartinfo">de.intevation.flys.exports.DischargeCurveInfoGenerator</output-generator> + <output-generator name="cross_section">de.intevation.flys.exports.CrossSectionGenerator</output-generator> + <output-generator name="cross_section_chartinfo">de.intevation.flys.exports.CrossSectionInfoGenerator</output-generator> + <output-generator name="computed_discharge_curve">de.intevation.flys.exports.ComputedDischargeCurveGenerator</output-generator> + <output-generator name="computed_discharge_curve_chartinfo">de.intevation.flys.exports.ComputedDischargeCurveInfoGenerator</output-generator> + <output-generator name="longitudinal_section">de.intevation.flys.exports.LongitudinalSectionGenerator</output-generator> + <output-generator name="longitudinal_section_chartinfo">de.intevation.flys.exports.LongitudinalSectionInfoGenerator</output-generator> + <output-generator name="duration_curve">de.intevation.flys.exports.DurationCurveGenerator</output-generator> + <output-generator name="duration_curve_chartinfo">de.intevation.flys.exports.DurationCurveInfoGenerator</output-generator> + <output-generator name="discharge_longitudinal_section">de.intevation.flys.exports.DischargeLongitudinalSectionGenerator</output-generator> + <output-generator name="discharge_longitudinal_section_chartinfo">de.intevation.flys.exports.DischargeLongitudinalSectionInfoGenerator</output-generator> + <output-generator name="waterlevel_export">de.intevation.flys.exports.WaterlevelExporter</output-generator> + <output-generator name="fix_wq_curve">de.intevation.flys.exports.fixings.FixWQCurveGenerator</output-generator> + <output-generator name="fix_wq_curve_chartinfo">de.intevation.flys.exports.fixings.FixWQCurveInfoGenerator</output-generator> + <output-generator name="durationcurve_export">de.intevation.flys.exports.DurationCurveExporter</output-generator> + <output-generator name="computed_dischargecurve_export">de.intevation.flys.exports.ComputedDischargeCurveExporter</output-generator> + <output-generator name="discharge_longitudinal_section_export">de.intevation.flys.exports.DischargeLongitudinalSectionExporter</output-generator> + <output-generator name="w_differences">de.intevation.flys.exports.WDifferencesCurveGenerator</output-generator> + <output-generator name="w_differences_chartinfo">de.intevation.flys.exports.WDifferencesCurveInfoGenerator</output-generator> + <output-generator name="w_differences_export">de.intevation.flys.exports.WDifferencesExporter</output-generator> + <output-generator name="floodmap">de.intevation.flys.exports.MapGenerator</output-generator> + <output-generator name="map">de.intevation.flys.exports.MapGenerator</output-generator> + <output-generator name="reference_curve">de.intevation.flys.exports.ReferenceCurveGenerator</output-generator> + <output-generator name="reference_curve_normalized">de.intevation.flys.exports.NormalizedReferenceCurveGenerator</output-generator> + <output-generator name="reference_curve_normalized_chartinfo">de.intevation.flys.exports.NormalizedReferenceCurveInfoGenerator</output-generator> + <output-generator name="reference_curve_chartinfo">de.intevation.flys.exports.ReferenceCurveInfoGenerator</output-generator> + <output-generator name="reference_curve_export">de.intevation.flys.exports.ReferenceCurveExporter</output-generator> + <output-generator name="historical_discharge">de.intevation.flys.exports.HistoricalDischargeCurveGenerator</output-generator> + <output-generator name="historical_discharge_chartinfo">de.intevation.flys.exports.HistoricalDischargeCurveInfoGenerator</output-generator> + <output-generator name="historical_discharge_export">de.intevation.flys.exports.HistoricalDischargeCurveExporter</output-generator> + <output-generator name="flow_velocity">de.intevation.flys.exports.FlowVelocityGenerator</output-generator> + <output-generator name="flow_velocity_chartinfo">de.intevation.flys.exports.FlowVelocityInfoGenerator</output-generator> + <output-generator name="flow_velocity_export">de.intevation.flys.exports.FlowVelocityExporter</output-generator> + <output-generator name="bedheight_middle">de.intevation.flys.exports.MiddleBedHeightGenerator</output-generator> + <output-generator name="bedheight_middle_chartinfo">de.intevation.flys.exports.MiddleBedHeightInfoGenerator</output-generator> + <output-generator name="bedheight_middle_export">de.intevation.flys.exports.MiddleBedHeightExporter</output-generator> + <output-generator name="bed_longitudinal_section">de.intevation.flys.exports.minfo.BedQualityGenerator</output-generator> + <output-generator name="bed_longitudinal_section_chartinfo">de.intevation.flys.exports.minfo.BedQualityInfoGenerator</output-generator> + <output-generator name="bed_quality_export">de.intevation.flys.exports.minfo.BedQualityExporter</output-generator> + <output-generator name="sq_relation_a">de.intevation.flys.exports.sq.SQRelationGeneratorA</output-generator> + <output-generator name="sq_relation_b">de.intevation.flys.exports.sq.SQRelationGeneratorB</output-generator> + <output-generator name="sq_relation_c">de.intevation.flys.exports.sq.SQRelationGeneratorC</output-generator> + <output-generator name="sq_relation_d">de.intevation.flys.exports.sq.SQRelationGeneratorD</output-generator> + <output-generator name="sq_relation_e">de.intevation.flys.exports.sq.SQRelationGeneratorE</output-generator> + <output-generator name="sq_relation_f">de.intevation.flys.exports.sq.SQRelationGeneratorF</output-generator> + <output-generator name="sq_relation_a_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_b_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_c_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_d_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_e_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_f_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator> + <output-generator name="sq_relation_export">de.intevation.flys.exports.sq.SQRelationExporter</output-generator> + <output-generator name="sq_overview">de.intevation.flys.exports.sq.SQOverviewGenerator</output-generator> + <output-generator name="fix_parameters_export">de.intevation.flys.exports.fixings.ParametersExporter</output-generator> + <output-generator name="fix_deltawt_export">de.intevation.flys.exports.fixings.DeltaWtExporter</output-generator> + <output-generator name="fix_deltawt_curve">de.intevation.flys.exports.fixings.FixDeltaWtGenerator</output-generator> + <output-generator name="fix_deltawt_curve_chartinfo">de.intevation.flys.exports.fixings.FixDeltaWtInfoGenerator</output-generator> + <output-generator name="fix_longitudinal_section_curve">de.intevation.flys.exports.fixings.FixLongitudinalSectionGenerator</output-generator> + <output-generator name="fix_longitudinal_section_curve_chartinfo">de.intevation.flys.exports.fixings.FixLongitudinalSectionInfoGenerator</output-generator> + <output-generator name="fix_derivate_curve">de.intevation.flys.exports.fixings.FixDerivedCurveGenerator</output-generator> + <output-generator name="fix_derivate_curve_chartinfo">de.intevation.flys.exports.fixings.FixDerivedCurveInfoGenerator</output-generator> + <output-generator name="fix_waterlevel_export">de.intevation.flys.exports.WaterlevelExporter</output-generator> + <output-generator name="fix_vollmer_wq_curve">de.intevation.flys.exports.fixings.FixWQCurveGenerator</output-generator> + <output-generator name="fix_vollmer_wq_curve_chartinfo">de.intevation.flys.exports.fixings.FixWQCurveInfoGenerator</output-generator> + <!-- Error report generators. --> + <output-generator name="discharge_longitudinal_section_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="waterlevel_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="computed_dischargecurve_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="durationcurve_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="wsplgen_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="historical_discharge_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="reference_curve_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <output-generator name="fix_report">de.intevation.flys.exports.ReportGenerator</output-generator> + <!-- AT exporter. --> + <output-generator name="computed_dischargecurve_at_export">de.intevation.flys.exports.ATExporter</output-generator> + <output-generator name="fix_wq_curve_at_export">de.intevation.flys.exports.fixings.FixATExport</output-generator> + </output-generators> + + <!-- Path to the template file of the meta data. --> + <metadata> + <template>${artifacts.config.dir}/meta-data.xml</template> + </metadata> + + &floodmap; + + &rest-server; + + <!-- Garbage collection of outdated artifacts. --> + <cleaner> + <sleep-time>60000</sleep-time> + </cleaner> + + <cache> + <config-file>${artifacts.config.dir}/cache.xml</config-file> + </cache> + + <!-- Configuration of used databases. --> + &artifact-db; + &datacage-db; + &backend-db; + &seddb-db; + + <flys> + <themes> + <configuration>${artifacts.config.dir}/themes.xml</configuration> + </themes> + </flys> +</artifact-database>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/datacage-db.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<datacage> + <user>SA</user> + <password/> + <driver>org.h2.Driver</driver> + <url>jdbc:h2:${artifacts.config.dir}/../h2/datacage</url> +</datacage>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/datacage.sql Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,104 @@ +BEGIN; + +CREATE SEQUENCE USERS_ID_SEQ; + +CREATE TABLE users ( + id INT PRIMARY KEY NOT NULL, + gid UUID NOT NULL UNIQUE +); + +CREATE SEQUENCE COLLECTIONS_ID_SEQ; + +CREATE TABLE collections ( + id INT PRIMARY KEY NOT NULL, + gid UUID NOT NULL UNIQUE, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + name VARCHAR(256) NOT NULL, + creation TIMESTAMP NOT NULL +); + +CREATE SEQUENCE ARTIFACTS_ID_SEQ; + +CREATE TABLE artifacts ( + id INT PRIMARY KEY NOT NULL, + gid UUID NOT NULL UNIQUE, + state VARCHAR(256) NOT NULL, + creation TIMESTAMP NOT NULL +); + +CREATE SEQUENCE COLLECTION_ITEMS_ID_SEQ; + +CREATE TABLE collection_items ( + id INT PRIMARY KEY NOT NULL, + collection_id INT NOT NULL REFERENCES collections(id) ON DELETE CASCADE, + artifact_id INT NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE +); + +CREATE SEQUENCE ARTIFACT_DATA_ID_SEQ; + +CREATE TABLE artifact_data ( + id INT PRIMARY KEY NOT NULL, + artifact_id INT NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE, + kind VARCHAR(256) NOT NULL, + k VARCHAR(256) NOT NULL, + v VARCHAR(256), -- Maybe too short + UNIQUE (artifact_id, k) +); + +CREATE SEQUENCE OUTS_ID_SEQ; + +CREATE TABLE outs ( + id INT PRIMARY KEY NOT NULL, + artifact_id INT NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE, + name VARCHAR(256) NOT NULL, + description VARCHAR(256), + out_type VARCHAR(256) +); + +CREATE SEQUENCE FACETS_ID_SEQ; + +CREATE TABLE facets ( + id INT PRIMARY KEY NOT NULL, + out_id INT NOT NULL REFERENCES outs(id) ON DELETE CASCADE, + name VARCHAR(256) NOT NULL, + num INT NOT NULL, + state VARCHAR(256) NOT NULL, + description VARCHAR(256), + UNIQUE (out_id, num, name) +); + +CREATE VIEW master_artifacts AS + SELECT a2.id AS id, + a2.gid AS gid, + a2.state AS state, + a2.creation AS creation, + ci2.collection_id AS collection_id + FROM collection_items ci2 + JOIN artifacts a2 + ON ci2.artifact_id = a2.id + JOIN (SELECT ci.collection_id AS c_id, + MIN(a.creation) AS oldest_a + FROM collection_items ci + JOIN artifacts a + ON ci.artifact_id = a.id + GROUP BY ci.collection_id) o + ON o.c_id = ci2.collection_id + WHERE a2.creation = o.oldest_a; + +-- DROP VIEW master_artifacts; +-- DROP SEQUENCE USERS_ID_SEQ; +-- DROP SEQUENCE COLLECTIONS_ID_SEQ; +-- DROP SEQUENCE ARTIFACTS_ID_SEQ; +-- DROP SEQUENCE COLLECTION_ITEMS_ID_SEQ; +-- DROP SEQUENCE ARTIFACT_DATA_ID_SEQ; +-- DROP SEQUENCE OUTS_ID_SEQ; +-- DROP SEQUENCE FACETS_ID_SEQ; +-- DROP TABLE facets; +-- DROP TABLE outs; +-- DROP TABLE artifact_data; +-- DROP TABLE collection_items; +-- DROP TABLE collections; +-- DROP TABLE artifacts; +-- DROP TABLE users; + +COMMIT;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/default-themes.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1568 @@ +<?xml version="1.0" encoding="UTF-8"?> +<themegroup name="default"> + <theme name="DischargeCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + <!-- concrete theme for historical discharge curves --> + <theme name="HistoricalDischargeCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + <theme name="HistoricalDischargeCurveQDiff"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + + <!-- Discharge Longitudinal Section --> + <theme name="LongitudinalSectionW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="bandwidth" type="double" display="Bandbreite" + default="0"/> + <field name="fillcolor" type="Color" display="Bandbreitenfarbe" + default="104, 104, 104"/> + <field name="transparency" type="int" default="20" display="Transparenz"/> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ2"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ5"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ10"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ20"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ25"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 51, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ50"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ100"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ200"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ500"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1000"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQRZ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HSQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MHQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 255, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MNQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 255, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 51, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_NQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 204, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQExtrem"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionPoints"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" /> + <field name="showpoints" type="boolean" display="Punkte anzeigen" + default="true" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ2_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ5_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ10_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ20_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ25_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 51, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ50_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 153, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ100_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ200_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ500_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1000_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQRZ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HSQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MHQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 255, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MNQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 255, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 51, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_NQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 204, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQExtrem_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <!-- Longitudinal Section Q's --> + + <theme name="LongitudinalSectionQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ1"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ2"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ5"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ10"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ20"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ25"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 51, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ50"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 153, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ100"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ200"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ500"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ1000"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQRZ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HSQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MHQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 255, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MNQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 255, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 51, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_NQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 204, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQExtrem"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <!-- Main Values --> + <theme name="MainValuesQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="200, 0, 15" /> + <field name="textcolor" type="Color" display="Farbe" + default="200, 0, 15" /> + <field name="showhorizontalline" type="boolean" + display="Horizontale Linie" default="true" /> + <field name="showverticalline" type="boolean" display="Vertikale Linie" + default="true" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <theme name="MainValuesW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="textcolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="showhorizontalline" type="boolean" + display="Horizontale Linie" default="true" /> + <field name="showverticalline" type="boolean" display="Vertikale Linie" + default="true" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Computed Discharge Curves --> + <theme name="ComputedDischargeCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + <theme name="ComputedDischargeCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="200, 0, 15" /> + <field name="textcolor" type="Color" display="Farbe" + default="200, 0, 15" /> + </fields> + </theme> + + <theme name="ComputedDischargeCurveW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="textcolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Cross Sections --> + <theme name="CrossSection"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,0,0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + <theme name="CrossSectionWaterLine"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,0,153" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="showwidth" type="boolean" display="Breite anzeigen" + default="false" /> + <field name="showlevel" type="boolean" display="Wasserstand anzeigen" + default="true" /> + <field name="showlinelabel" type="boolean" default="true" + display="Beschriftung anzeigen" /> + <field name="showmiddleheight" type="boolean" + display="Wasserstand anzeigen" default="false" /> + </fields> + </theme> + + <theme name="Hyk"> + <inherits> + <inherit from="Text" /> + </inherits> + <fields> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Relative Points --> + <theme name="RelativePoint"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <!--fields> <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0"/> </fields --> + </theme> + + <!-- Duration Curves --> + <theme name="DurationCurveW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,51,204" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + <theme name="DurationCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,204,0" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hints="h" /> + </fields> + </theme> + + <!-- Differences --> + <theme name="Differences"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <!-- Reference Curves --> + <theme name="ReferenceCurveNormalized"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="ReferenceCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <!-- General --> + <theme name="WKms"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="WQKms"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="WQPoints"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" /> + <field name="showpoints" type="boolean" display="Punkte anzeigen" + default="true" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 0" /> + </fields> + </theme> + + <!-- Discharge Longitudinal Section --> + <theme name="DischargeLongitudinalSectionW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + + <theme name="DischargeLongitudinalSectionC"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0 , 0" /> + </fields> + </theme> + + <theme name="DischargeLongitudinalSectionQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + + <!-- Annotations --> + <theme name="Annotations"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + <inherit from="AnnotationText" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <!-- Manual Points --> + <theme name="ManualPoints"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="250, 0, 0" /> + <field name="font" type="Font" display="Schriftart" + default="arial" /> + <field name="textcolor" type="Color" display="Schriftfarbe" + default="0, 0, 0" /> + <field name="textsize" type="int" display="Schriftgröße" + default="10" /> + <field name="textstyle" type="Style" display="Schriftstil" + default="standard" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" hints="h" /> + <field name="backgroundcolor" type="Color" display="Texthintergrund" + default="255, 255, 255" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + <field name="showbackground" type="boolean" + display="Hintergrund anzeigen" default="false" /> + </fields> + </theme> + + <!-- Height Marks --> + <theme name="heightmarks_points"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <!-- Areas --> + <theme name="Area"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="showarea" type="boolean" display="Show Area" + default="true"/> + </fields> + </theme> + + <!-- Map --> + <theme name="Floodmaps"> + <inherits> + <inherit from="Floodmap" /> + </inherits> + </theme> + + <theme name="Floodplains"> + <inherits> + <inherit from="Floodplain" /> + </inherits> + </theme> + + <theme name="WSPLGEN"> + <inherits> + <inherit from="WSPLGENS" /> + </inherits> + </theme> + + <theme name="RiverAxis"> + <inherits> + <inherit from="RiverAxes" /> + </inherits> + </theme> + + <theme name="Kms"> + <inherits> + <inherit from="Km" /> + </inherits> + </theme> + + + <theme name="Fixpoints"> + <inherits> + <inherit from="Fixpoint" /> + </inherits> + </theme> + + + <theme name="GaugeLocation"> + <inherits> + <inherit from="GaugeLocations" /> + </inherits> + </theme> + + + <theme name="Qps"> + <inherits> + <inherit from="Qp" /> + </inherits> + </theme> + + <theme name="Hws"> + <inherits> + <inherit from="Hw" /> + </inherits> + </theme> + + <theme name="Catchment"> + <inherits> + <inherit from="Catchments" /> + </inherits> + </theme> + + <theme name="FloodmapLines"> + <inherits> + <inherit from="FloodmapLine" /> + </inherits> + </theme> + + <theme name="Buildings"> + <inherits> + <inherit from="Building" /> + </inherits> + </theme> + + <theme name="HydrBoundariesLines"> + <inherits> + <inherit from="HydrBoundariesLine" /> + </inherits> + </theme> + + <theme name="HydrBoundariesPolys"> + <inherits> + <inherit from="HydrBoundariesPoly" /> + </inherits> + </theme> + + <!-- MIDDLE BED HEIGHT --> + <theme name="MiddleBedHeightSingle"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="MiddleBedHeightEpoch"> + <inherits> + <inherit from="FlowVelocityVMainChannel" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <!-- Bed Quality --> + <theme name="PorosityTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="PorositySubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + </fields> + </theme> + + <theme name="DensityTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#996366" /> + </fields> + </theme> + + <theme name="DensitySubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#996366" /> + </fields> + </theme> + + <theme name="BedDiameterTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#FF0000" /> + </fields> + </theme> + + <theme name="BedDiameterSubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#FF0000" /> + </fields> + </theme> + + <theme name="BedLoadDiameter"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#00FF00" /> + </fields> + </theme> + + + <!-- FLOW VELOCITY --> + <theme name="FlowVelocityVMainChannel"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + </fields> + </theme> + + <theme name="FlowVelocityVTotalChannel"> + <inherits> + <inherit from="FlowVelocityVMainChannel" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 102" /> + </fields> + </theme> + + <theme name="FlowVelocityTau"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 204" /> + </fields> + </theme> + + + <!-- SQ Relation --> + <theme name="SQMeasurements"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" hidden="true" /> + <field name="pointcolor" type="Color" default="#0099FF" /> + </fields> + </theme> + + <theme name="SQOutliers"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" hidden="true" /> + <field name="pointcolor" type="Color" default="#CC0000" /> + </fields> + </theme> + + <theme name="SQCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="#000000" /> + </fields> + </theme> + + <theme name="FixingWQCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="227, 27, 162" /> + </fields> + </theme> + + <theme name="FixingDerivedCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="227, 27, 162" /> + <field name="showpoints" type="boolean" display="Datenpunkte anzeigen" + default="false" hints="h" hidden="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5" hints="h" hidden="true" /> + </fields> + </theme> + + <theme name="FixingSectorAverageWQ0"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="true" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 128, 0" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ1"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 0, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ2"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="255, 0, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ3"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="255, 0, 0" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + + <theme name="FixingAnalysisEventsWQ"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 255, 0" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + + <theme name="FixingReferenceEvents"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="false" + hidden="true" /> + <field name="showlinelabel" type="boolean" default="false" + hidden="true" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" hidden="true" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hidden="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 80, 160" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + + <theme name="FixingOutliers"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingDeltaWtAverage0"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 128, 0" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage1"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 255" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage2"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage3"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + + <theme name="FixingDeltaWtAnalysis"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 255, 0" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + + <theme name="FixingLSAverage0"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 128, 0" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage1"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 0, 255" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage2"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="255, 0, 255" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage3"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="255, 0, 0" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + + <theme name="FixingSectorDeviationLS0"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="0, 128, 0" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS1"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="0, 0, 255" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS2"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="255, 0, 255" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS3"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="255, 0, 0" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixLSDeviation"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="100, 100, 100" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixLSAnalysis"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 255, 0" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixLSReference"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 80, 160" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixDeltaWtDeviation"> + <inherits> + <inherit from="Areas"/> + </inherits> + <fields> + <field name="transparency" type="int" default="80" display="Transparenz"/> + <field name="backgroundcolor" type="Color" default="0, 0, 0" display="Füllfarbe"/> + </fields> + </theme> + <theme name="FixingDeltaWtAnalysisPeriods"> + <inherits> + <inherit from="Areas"/> + </inherits> + <fields> + <field name="transparency" type="int" default="80" display="Transparenz"/> + <field name="backgroundcolor" type="Color" default="255, 0, 0" display="Füllfarbe" /> + </fields> + </theme> + + <theme name="QSectors"> + <fields> + <field name="linecolor" type="Color" default="227, 27, 162" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" hidden="true" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hidden="true" /> + <field name="labelfontface" type="Font" + display="Beschriftung: Schriftart" default="arial" /> + <field name="labelfontcolor" type="Color" + display="Beschriftung: Schriftfarbe" default="0, 0, 0" /> + <field name="labelfontsize" type="int" + display="Beschriftung: Schriftgröße" default="10" /> + <field name="labelfontstyle" type="Style" + display="Beschriftung: Schriftstil" default="standard" /> + </fields> + </theme> + +</themegroup>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/floodmap.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<floodmap> + <shapefile-path value="${artifacts.config.dir}/../shapefiles"/> + <mapserver> + <server path="http://flys-devel.intevation.de/cgi-bin/"/> + <mapfile path="${artifacts.config.dir}/../flys.map"/> + <templates path="${artifacts.config.dir}/mapserver/"/> + <map-template path="mapfile.vm"/> + </mapserver> + + <velocity> + <logfile path="${artifacts.config.dir}/../velocity_log.log"/> + </velocity> + + <river name="Saar"> + <srid value="31466"/> + <river-wms url="http://flys-devel.intevation.de/cgi-bin/saar-wms"/> + <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/> + </river> + <river name="Mosel"> + <srid value="31466"/> + <river-wms url="http://flys-devel.intevation.de/cgi-bin/mosel-wms"/> + <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/> + </river> + <river name="Elbe"> + <srid value="31466"/> + <river-wms url="http://flys-devel.intevation.de/cgi-bin/elbe-wms"/> + <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/> + </river> +</floodmap>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/barrier_lines_class.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,32 @@ +CLASS + NAME "Damm" + EXPRESSION ("[TYP]"="Damm") + STYLE + SIZE 5 + OUTLINECOLOR "#008000" + END +END +CLASS + NAME "Rohr 1" + EXPRESSION ("[TYP]"="Rohr 1") + STYLE + SIZE 5 + OUTLINECOLOR "#800080" + END +END +CLASS + NAME "Rohr 2" + EXPRESSION ("[TYP]"="Rohr 2") + STYLE + SIZE 5 + OUTLINECOLOR "#808080" + END +END +CLASS + NAME "Graben" + EXPRESSION ("[TYP]"="Graben") + STYLE + SIZE 5 + OUTLINECOLOR "#800000" + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/barrier_polygons_class.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,7 @@ +CLASS + NAME "POLYGON_BARRIERS" + STYLE + SIZE 5 + OUTLINECOLOR "#FF8000" + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/db_layer.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,58 @@ +LAYER + NAME "$LAYER.getName()" + TYPE $LAYER.getType() + + CONNECTIONTYPE $LAYER.getConnectionType() + CONNECTION "$LAYER.getConnection()" + + DATA "$LAYER.getData()" + FILTER "$LAYER.getFilter()" + EXTENT $LAYER.getExtent() + + STATUS ON + TEMPLATE map.html + TOLERANCE 10 + DUMP TRUE + #if( $LAYER.getGroup() ) + GROUP "$LAYER.getGroup()" + #end + + #if ( $LAYER.getLabelItem() ) + LABELITEM $LAYER.getLabelItem() + #end + + PROJECTION + "init=epsg:$LAYER.getSrid()" + END + + METADATA + "wms_title" "$LAYER.getTitle()" + "gml_include_items" "all" + #if ( $LAYER.getGroupTitle() ) + "wms_group_title" "$LAYER.getGroupTitle()" + #end + END + + #if ( $LAYER.getStyle() ) + $LAYER.getStyle() + #else + CLASS + NAME "" + STYLE + SIZE 5 + OUTLINECOLOR "#000000" + END + #if ( $LAYER.getLabelItem() ) + LABEL + ANGLE auto + SIZE 10 + COLOR "#000000" + TYPE truetype + FONT LiberationSans-Italic + POSITION ur + OFFSET 2 2 + END + #end + END + #end +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/fontset.txt Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,2 @@ +FreeSans /usr/share/fonts/truetype/freefont/FreeSans.ttf +DefaultFont /usr/share/fonts/truetype/freefont/FreeSans.ttf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/layer.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,38 @@ +LAYER + NAME "$LAYER.getName()" + TYPE $LAYER.getType() + DATA "$LAYER.getDirectory()/$LAYER.getData()" + STATUS ON + TEMPLATE map.html + TOLERANCE 10 + DUMP TRUE + #if( $LAYER.getGroup() ) + GROUP "$LAYER.getGroup()" + #end + + METADATA + "wms_title" "$LAYER.getTitle()" + "gml_include_items" "all" + #if ( $LAYER.getGroupTitle() ) + "wms_group_title" "$LAYER.getGroupTitle()" + #end + END + + PROJECTION + "init=epsg:$LAYER.getSrid()" + END + + #if ( !$LAYER.getStyle() ) + #if ( $LAYER.getGroupTitle() ) + #if ( $LAYER.getType() == "POLYGON" ) + #include("barrier_polygons_class.vm") + #else + #include("barrier_lines_class.vm") + #end + #else + #include("wsplgen_class.vm") + #end + #else + $LAYER.getStyle() + #end +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/mapfile.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,60 @@ +MAP + NAME "FLYS-Map" + STATUS ON + SIZE 600 400 + MAXSIZE 4000 + EXTENT -90 -180 90 180 + UNITS DD + SHAPEPATH "$SHAPEFILEPATH" + FONTSET "$CONFIGDIR/mapserver/fontset.txt" + SYMBOLSET "$CONFIGDIR/mapserver/symbols.sym" + IMAGECOLOR 255 255 255 + PROJECTION + "init=epsg:31466" + END + + DEBUG 5 + CONFIG "MS_ERRORFILE" "/tmp/flys-user-wms.log" + + WEB + METADATA + "wms_title" "FLYS Web Map Service" + "wms_onlineresource" "$MAPSERVERURL" + "wms_accessconstraints" "none" + "wms_fees" "none" + "wms_addresstype" "postal" + "wms_address" "Any Street" + "wms_city" "Any City" + "wms_stateorprovince" "Any state" + "wms_postcode" "My Postalcode" + "wms_country" "Any Country" + "wms_contactperson" "Any Person" + "wms_contactorganization" "Any Orga" + "wms_contactelectronicmailaddress" "any-email@example.com" + "wms_contactvoicetelephone" "Any's telephone number" + "wms_srs" "EPSG:4326 EPSG:31466 EPSG:31467" + "wms_feature_info_mime_type" "text/html" + "ows_enable_request" "*" + END + END + + LEGEND + KEYSIZE 20 20 + STATUS ON + TRANSPARENT ON + + LABEL + COLOR 150 150 150 + OUTLINECOLOR 255 255 255 + TYPE truetype + FONT "FreeSans" + SIZE 12 + POSITION AUTO + END + END + + ## Don't change the following lines. + #foreach ($LAYER in $LAYERS) + include "$LAYER" + #end +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/shapefile_layer.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,38 @@ +LAYER + NAME "$LAYER.getName()" + TYPE $LAYER.getType() + DATA "$LAYER.getDirectory()/$LAYER.getData()" + STATUS ON + TEMPLATE map.html + TOLERANCE 10 + DUMP TRUE + #if( $LAYER.getGroup() ) + GROUP "$LAYER.getGroup()" + #end + + PROJECTION + "init=epsg:$LAYER.getSrid()" + END + + METADATA + "wms_title" "$LAYER.getTitle()" + "gml_include_items" "all" + #if ( $LAYER.getGroupTitle() ) + "wms_group_title" "$LAYER.getGroupTitle()" + #end + END + + #if ( !$LAYER.getStyle() ) + #if ( $LAYER.getGroupTitle() ) + #if ( $LAYER.getType() == "POLYGON" ) + #include("barrier_polygons_class.vm") + #else + #include("barrier_lines_class.vm") + #end + #else + #include("wsplgen_class.vm") + #end + #else + $LAYER.getStyle() + #end +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/symbols.sym Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,22 @@ +SYMBOLSET +SYMBOL + NAME 'point' + TYPE ELLIPSE + POINTS + 1 1 + END + FILLED TRUE +END +SYMBOL + NAME "square" + TYPE VECTOR + POINTS + 0 0 + 0 1 + 1 1 + 1 0 + 0 0 + END + FILLED TRUE +END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/wsplgen_class.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,44 @@ +CLASS + NAME "0.0 <= DIFF < 1" + EXPRESSION ([DIFF] < 1) + STYLE + SIZE 5 + COLOR "#B2C9D7" + END +END + +CLASS + NAME "1.0 <= DIFF < 2" + EXPRESSION ([DIFF] >= 1 AND [DIFF] < 2) + STYLE + SIZE 5 + COLOR "#6F93AA" + END +END + +CLASS + NAME "2.0 <= DIFF < 3" + EXPRESSION ([DIFF] >= 2 AND [DIFF] < 3) + STYLE + SIZE 5 + COLOR "#426F8B" + END +END + +CLASS + NAME "3.0 <= DIFF < 4" + EXPRESSION ([DIFF] >= 3 AND [DIFF] < 4) + STYLE + SIZE 5 + COLOR "#214F6C" + END +END + +CLASS + NAME "Sonstiges" + EXPRESSION ([DIFF] >= 4) + STYLE + SIZE 5 + COLOR "#021B2A" + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/mapserver/wsplgen_layer.vm Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,40 @@ +LAYER + NAME "$LAYER.getName()" + TYPE $LAYER.getType() + DATA "$LAYER.getDirectory()/$LAYER.getData()" + STATUS ON + TEMPLATE map.html + TOLERANCE 10 + DUMP TRUE + #if( $LAYER.getGroup() ) + GROUP "$LAYER.getGroup()" + #end + + PROJECTION + "init=epsg:$LAYER.getSrid()" + END + + METADATA + "wms_title" "$LAYER.getTitle()" + "gml_include_items" "all" + "ows_enable_request" "GetFeatureInfo" + "wms_feature_info_mime_type" "gml" + #if ( $LAYER.getGroupTitle() ) + "wms_group_title" "$LAYER.getGroupTitle()" + #end + END + + #if ( !$LAYER.getStyle() ) + #if ( $LAYER.getGroupTitle() ) + #if ( $LAYER.getType() == "POLYGON" ) + #include("barrier_polygons_class.vm") + #else + #include("barrier_lines_class.vm") + #end + #else + #include("wsplgen_class.vm") + #end + #else + $LAYER.getStyle() + #end +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/meta-data.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1890 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<dc:template xmlns:dc="http://www.intevation.org/2011/Datacage"> +<datacage> + <dc:macro name="load-system"> + <dc:context connection="system"> + <dc:statement> + SELECT id AS river_id, name as river_name FROM rivers + WHERE lower(name) LIKE lower(${river}) + </dc:statement> + <dc:elements> + <dc:comment> + Base-data macros (mostly data imported from wst-files) + </dc:comment> + <dc:macro name="basedata_0"> + <dc:comment comment=" BASEDATA ---------------------------"/> + <basedata> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 0 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <basedata> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="base_data-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </basedata> + </dc:elements> + </dc:context> + </basedata> + </dc:macro> + <dc:macro name="basedata_0_wq"> + <dc:comment comment=" BASEDATA ---------------------------"/> + <basedata> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 0 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <basedata> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="base_data-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="wqinterpol"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </basedata> + </dc:elements> + </dc:context> + </basedata> + </dc:macro> + + <dc:macro name="basedata_1_additionals"> + <dc:comment comment=".ZUS -------------------------------"/> + <additionals> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <additional> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </additional> + </dc:elements> + </dc:context> + </additionals> + </dc:macro> + + <dc:macro name="basedata_1_additionals-relative_point"> + <dc:comment comment=".ZUS -------------------------------"/> + <additionals> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <relativepoint> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </relativepoint> + </dc:elements> + </dc:context> + </additionals> + </dc:macro> + + <dc:macro name="basedata_2_fixations_wst"> + <fixations> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 2 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <fixation> + <dc:attribute name="name" value="${prot_description}"/> + <!--dc:attribute name="ids" value="fixations-wstv-A-${prot_id}"/--> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="wqinterpol"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </fixation> + </dc:elements> + </dc:context> + </fixations> + </dc:macro> + + <dc:macro name="basedata_2_fixations_wqkms"> + <fixations> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 2 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <fixation> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + desciption AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="wqinterpol"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </fixation> + </dc:elements> + </dc:context> + </fixations> + </dc:macro> + + <dc:macro name="basedata_2_fixations"> + <fixations> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 2 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <fixation> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </fixation> + </dc:elements> + </dc:context> + </fixations> + </dc:macro> + + <dc:macro name="basedata_2_fixations_relative_point"> + <fixations> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 2 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <relativepoint> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </relativepoint> + </dc:elements> + </dc:context> + </fixations> + </dc:macro> + + <dc:macro name="basedata_3_officials"> + <dc:comment comment=".wst -------------------------------"/> + <officiallines> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 3 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <official> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </official> + </dc:elements> + </dc:context> + </officiallines> + </dc:macro> + + <dc:macro name="basedata_4_heightmarks-points-relative_points"> + <heightmarks> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 4 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <relativepoint> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="heightmarks_points-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </relativepoint> + </dc:elements> + </dc:context> + </heightmarks> + </dc:macro> + + <dc:macro name="basedata_4_heightmarks-points"> + <heightmarks> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 4 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <heightmark> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="heightmarks_points-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </heightmark> + </dc:elements> + </dc:context> + </heightmarks> + </dc:macro> + + <dc:macro name="basedata_4_heightmarks-wq"> + <heightmarks> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 4 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <heightmark> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="heightmarks_annotations-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="wqinterpol"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </heightmark> + </dc:elements> + </dc:context> + </heightmarks> + </dc:macro> + + <dc:macro name="basedata_5_flood-protections_relative_points"> + <flood_protections> + <dc:attribute name="id" value="flood-protections-${river_id}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 5 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <relativepoint> + <dc:attribute name="name" value="${prot_description}"/> + <dc:attribute name="db-id" value="${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <columns> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos, + description AS info + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="flood_protection-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <dc:attribute name="info" value="${info}"/> + </column> + </dc:elements> + </dc:context> + </columns> + </relativepoint> + </dc:elements> + </dc:context> + </flood_protections> + </dc:macro> + + <dc:macro name="basedata_5_flood-protections"> + <flood_protections> + <dc:attribute name="id" value="flood-protections-${river_id}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 5 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <flood_protection> + <dc:attribute name="name" value="${prot_description}"/> + <dc:attribute name="db-id" value="${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + <columns> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="flood_protection-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + </column> + </dc:elements> + </dc:context> + </columns> + </flood_protection> + </dc:elements> + </dc:context> + </flood_protections> + </dc:macro> + + <dc:macro name="mainvalues"> + <mainvalue> + <dc:attribute name="factory" value="mainvalue"/> + <dc:attribute name="ids" value="${river_id}"/> + </mainvalue> + </dc:macro> + + <dc:macro name="qsectors"> + <qsector> + <dc:attribute name="factory" value="qsectors"/> + <dc:attribute name="ids" value="${river_id}"/> + </qsector> + </dc:macro> + + <dc:macro name="annotations"> + <annotation> + <dc:attribute name="factory" value="annotations"/> + <dc:attribute name="ids" value="${river_id}"/> + </annotation> + </dc:macro> + + <dc:macro name="cross_sections"> + <cross_sections> + <dc:attribute name="id" value="flood-protections-${river_id}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM cross_sections WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <cross_section> + <dc:attribute name="name" value="${prot_description}"/> + <dc:attribute name="ids" value="${prot_id}"/> + <dc:attribute name="factory" value="crosssections"/> + </cross_section> + </dc:elements> + </dc:context> + </cross_sections> + </dc:macro> + + <dc:macro name="hyks"> + <hyks> + <dc:attribute name="id" value="hyk-${river_id}"/> + <dc:context> + <dc:statement> + SELECT id AS hyk_id, + description AS hyk_description + FROM hyks WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <hyk> + <dc:attribute name="name" value="${hyk_description}"/> + <dc:attribute name="ids" value="${hyk_id}"/> + <dc:attribute name="factory" value="hyk"/> + </hyk> + </dc:elements> + </dc:context> + </hyks> + </dc:macro> + + <dc:comment> + + + River-Node + + </dc:comment> + + <river> + <dc:attribute name="name" value="${river_name}"/> + + <dc:choose> + <dc:when test="dc:contains($parameters, 'recommended')"> + <dc:comment> + Recommendations (client shall load immediately). + </dc:comment> + <dc:if test="dc:contains($artifact-outs, 'w_differences') or (dc:contains($artifact-outs, 'discharge_longitudinal_section'))"> + <dc:call-macro name="annotations"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'cross_section')"> + <dc:call-macro name="cross_sections"/> + <dc:call-macro name="hyks"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'reference_curve')"> + <dc:call-macro name="annotations"/> + <dc:call-macro name="mainvalues"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')"> + <dc:call-macro name="qsectors"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')"> + <dc:call-macro name="annotations"/> + </dc:if> + </dc:when> + <dc:otherwise> + <dc:comment> + Non - Recommendations. + </dc:comment> + <dc:if test="dc:contains($artifact-outs, 'cross_section')"> + <dc:call-macro name="basedata_0"/> + <dc:call-macro name="basedata_1_additionals"/> + <dc:call-macro name="basedata_2_fixations"/> + <dc:call-macro name="basedata_3_officials"/> + <dc:call-macro name="basedata_4_heightmarks-points"/> + <dc:call-macro name="cross_sections"/> + <dc:call-macro name="hyks"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'discharge_longitudinal_section')"> + <dc:call-macro name="basedata_0"/> + <dc:call-macro name="basedata_1_additionals"/> + <dc:call-macro name="basedata_2_fixations"/> + <dc:call-macro name="basedata_3_officials"/> + <dc:call-macro name="basedata_4_heightmarks-points"/> + <dc:call-macro name="basedata_5_flood-protections"/> + </dc:if> + <!--dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')"> + <dc:call-macro name="basedata_0_wq"/> + <dc:call-macro name="basedata_4_heightmarks-wq"/> + </dc:if--> + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section') or (dc:contains($artifact-outs, 'w_differences'))"> + <dc:call-macro name="basedata_0"/> + <dc:call-macro name="basedata_1_additionals"/> + <dc:comment comment=" FIXATIONS ---------------------------"/> + <dc:call-macro name="basedata_2_fixations"/> + <dc:comment comment=" HOEHENMARKEN ---------------------------"/> + <dc:call-macro name="basedata_4_heightmarks-points"/> + <dc:comment comment=" AMTL LINIEN ---------------------------"/> + <dc:call-macro name="basedata_3_officials"/> + <dc:call-macro name="annotations"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'reference_curve')"> + <dc:call-macro name="annotations"/> + <!--dc:call-macro name="basedata_0"/--> + <dc:call-macro name="basedata_1_additionals-relative_point"/> + <dc:comment comment=" FIXATIONS ---------------------------"/> + <dc:call-macro name="basedata_2_fixations_relative_point"/> + <dc:comment comment=" HOEHENMARKEN ---------------------------"/> + <dc:call-macro name="basedata_4_heightmarks-points-relative_points"/> + <dc:call-macro name="basedata_5_flood-protections_relative_points"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')"> + <dc:call-macro name="basedata_0_wq"/> + <dc:call-macro name="basedata_1_additionals"/> + <dc:call-macro name="basedata_2_fixations"/> + <dc:call-macro name="basedata_3_officials"/> + <dc:call-macro name="basedata_4_heightmarks-points"/> + <dc:call-macro name="basedata_5_flood-protections_relative_points"/> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'fix_deltawt_curve')"> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')"> + <dc:call-macro name="annotations"/> + </dc:if> + <dc:comment comment="--- non-recommendations---"/> + </dc:otherwise> + </dc:choose> + + + <dc:if test="dc:contains($artifact-outs, 'waterlevels')"> + + <!-- base data --> + <dc:call-macro name="basedata_0"/> + + <!-- extra-longitudinal-sections --> + <dc:call-macro name="basedata_1_additionals"/> + + <!-- fixations --> + <dc:call-macro name="basedata_2_fixations"/> + + <!-- flood water marks--> + <dc:call-macro name="basedata_4_heightmarks-points"/> + + <!-- flood protection --> + <dc:call-macro name="basedata_5_flood-protections"/> + + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve') and (dc:contains($parameters, 'recommended'))"> + <!--dc:call-macro name="basedata_2_fixations_wst"/--> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve') and not (dc:contains($parameters, 'recommended'))"> + <discharge_table_nn> + <discharge_table_gauge> + <dc:context> + <dc:statement> + SELECT id AS gauge_id, + name AS gauge_name + FROM gauges WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <gauge> + <dc:attribute name="name" value="${gauge_name}"/> + <dc:attribute name="db-id" value="${gauge_id}"/> + <dc:attribute name="factory" value="gaugedischarge"/> + <dc:attribute name="from" value="${g_start}"/> + <dc:attribute name="to" value="${g_stop}"/> + <dc:attribute name="ids" value="${gauge_name}"/> + </gauge> + <!-- + <gauge> + <dc:attribute name="name" value="${gauge_name}"/> + <dc:attribute name="db-id" value="${gauge_id}"/> + <dc:context> + <dc:statement> + SELECT description AS gauge_desc, + d.id AS discharge_id, + ti.start_time AS g_start, + ti.stop_time AS g_stop + FROM discharge_tables d JOIN time_intervals ti + ON d.time_interval_id = ti.id + WHERE d.gauge_id = ${gauge_id} AND d.kind = 1 + </dc:statement> + <dc:elements> + <historical> + <dc:attribute name="name" value="${gauge_desc}"/> + <dc:attribute name="factory" value="gaugedischarge"/> + <dc:attribute name="from" value="${g_start}"/> + <dc:attribute name="to" value="${g_stop}"/> + <dc:attribute name="ids" value="${discharge_id}-${g_start}-${g_stop}"/> + </historical> + </dc:elements> + </dc:context> + </gauge> + --> + </dc:elements> + </dc:context> + </discharge_table_gauge> + + </discharge_table_nn> + + <dc:call-macro name="basedata_2_fixations_wst"/> + + <dc:call-macro name="basedata_5_flood-protections"/> + + <!-- former waterlevels --> + <dc:call-macro name="basedata_0"/> + + <dc:call-macro name="basedata_1_additionals"/> + + <!-- former flood-water-marks --> + <dc:call-macro name="basedata_4_heightmarks-points"/> + <computed_discharge_curve> + <dc:call-macro name="mainvalues"/> + </computed_discharge_curve> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'duration_curve')"> + <dc:choose> + <dc:when test="dc:contains($parameters, 'recommended')"> + <dc:call-macro name="mainvalues"/> + </dc:when> + <dc:otherwise> + <dc:call-macro name="mainvalues"/> + <dc:call-macro name="basedata_2_fixations_relative_point"/> + <dc:call-macro name="basedata_4_heightmarks-points-relative_points"/> + <dc:call-macro name="basedata_5_flood-protections_relative_points"/> + </dc:otherwise> + </dc:choose> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve') and not (dc:contains($parameters, 'recommended'))"> + <discharge_table_nn> + <discharge_table_gauge> + <dc:context> + <dc:statement> + SELECT id AS gauge_id, + name AS gauge_name + FROM gauges WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <gauge> + <dc:attribute name="name" value="${gauge_name}"/> + <dc:attribute name="db-id" value="${gauge_id}"/> + <dc:attribute name="factory" value="gaugedischarge"/> + <dc:attribute name="from" value="${g_start}"/> + <dc:attribute name="to" value="${g_stop}"/> + <dc:attribute name="ids" value="${gauge_name}"/> + </gauge> + </dc:elements> + </dc:context> + </discharge_table_gauge> + </discharge_table_nn> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')"> + + <longitudinal_section> + <dc:call-macro name="annotations"/> + </longitudinal_section> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'map')"> + <map> + <dc:choose> + <dc:when test="dc:contains($parameters, 'recommended')"> + </dc:when> + <dc:otherwise> + <dc:call-macro name="flood-map-complete"/> + </dc:otherwise> + </dc:choose> + </map> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'floodmap')"> + <floodmap> + <dc:choose> + <dc:when test="dc:contains($parameters, 'recommended')"> + <dc:call-macro name="flood-map-recommended"/> + </dc:when> + <dc:when test="dc:contains($parameters, 'dem')"> + <dc:call-macro name="flood-map-dem"/> + </dc:when> + <dc:otherwise> + <dc:call-macro name="flood-map-complete"/> + </dc:otherwise> + </dc:choose> + </floodmap> + <dc:macro name="flood-map-recommended"> + <dc:comment> + FIXME: Following two macros look identical to me. + </dc:comment> + <kilometrage> + <riveraxis> + <dc:attribute name="factory" value="riveraxis"/> + <dc:attribute name="ids" value="${river_id}"/> + </riveraxis> + </kilometrage> + <rastermap> + <background> + <dc:attribute name="factory" value="wmsbackground"/> + <dc:attribute name="ids" value="${river_id}"/> + </background> + </rastermap> + </dc:macro> + <dc:macro name="flood-map-dem"> + <dems> + <dc:context> + <dc:statement> + SELECT id AS dem_id, + lower AS dem_lower, + upper AS dem_upper + FROM dem WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <dem> + <dc:attribute name="factory" value="demfactory"/> + <dc:attribute name="ids" value="${dem_id}"/> + <dc:attribute name="description" value="${dem_lower}-${dem_upper}"/> + </dem> + </dc:elements> + </dc:context> + </dems> + </dc:macro> + <dc:macro name="flood-map-km"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists + FROM river_axes_km WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <km> + <dc:attribute name="factory" value="wmskmfactory"/> + <dc:attribute name="ids" value="${river_id}"/> + </km> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-qps"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists + FROM cross_section_tracks WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <qps> + <dc:attribute name="factory" value="wmsqpsfactory"/> + <dc:attribute name="ids" value="${river_id}"/> + </qps> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-hws"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM hws WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <hws> + <dc:attribute name="factory" value="wmshwsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </hws> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-hydr-boundaries"> + <hydr_boundaries_lines> + <dc:call-macro name="flood-map-hydr-boundaries-lines"/> + </hydr_boundaries_lines> + <hydr_boundaries_polygons> + <dc:call-macro name="flood-map-hydr-boundaries-poly"/> + </hydr_boundaries_polygons> + </dc:macro> + <dc:macro name="flood-map-hydr-boundaries-lines"> + <bfg> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM hydr_boundaries WHERE river_id = ${river_id} AND kind = 1 GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <hydrboundary> + <dc:attribute name="factory" value="wmshydrboundariesfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </hydrboundary> + </dc:if> + </dc:elements> + </dc:context> + </bfg> + <land> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM hydr_boundaries WHERE river_id = ${river_id} AND kind = 2 GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <hydrboundary> + <dc:attribute name="factory" value="wmshydrboundariesfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </hydrboundary> + </dc:if> + </dc:elements> + </dc:context> + </land> + </dc:macro> + <dc:macro name="flood-map-hydr-boundaries-poly"> + <bfg> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM hydr_boundaries_poly WHERE river_id = ${river_id} AND kind = 1 GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <hws> + <dc:attribute name="factory" value="wmshydrboundariespolyfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </hws> + </dc:if> + </dc:elements> + </dc:context> + </bfg> + <land> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM hydr_boundaries_poly WHERE river_id = ${river_id} AND kind = 2 GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <hws> + <dc:attribute name="factory" value="wmshydrboundariespolyfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </hws> + </dc:if> + </dc:elements> + </dc:context> + </land> + </dc:macro> + <dc:macro name="flood-map-catchments"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM catchment WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <catchment> + <dc:attribute name="factory" value="wmscatchmentfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </catchment> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-floodplain"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists + FROM floodplain WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <floodplain> + <dc:attribute name="factory" value="wmsfloodplainfactory"/> + <dc:attribute name="ids" value="${river_id}"/> + </floodplain> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-lines"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM lines WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <line> + <dc:attribute name="factory" value="wmslinefactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </line> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-buildings"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM buildings WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <building> + <dc:attribute name="factory" value="wmsbuildingsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </building> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-fixpoints"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM fixpoints WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <fixpoint> + <dc:attribute name="factory" value="wmsfixpointsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </fixpoint> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-gaugelocations"> + <dc:context> + <dc:statement> + SELECT count(*) as km_exists, name as name + FROM gauge_location WHERE river_id = ${river_id} GROUP BY name + </dc:statement> + <dc:elements> + <dc:if test="$km_exists>0"> + <gaugelocation> + <dc:attribute name="factory" value="wmsgaugelocationfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </gaugelocation> + </dc:if> + </dc:elements> + </dc:context> + </dc:macro> + <dc:macro name="flood-map-uesk"> + <uesk> + <calculations> + <current> + <bfg> + <dc:context> + <dc:statement> + SELECT count(*) as uesg_exist, name as name + FROM floodmaps + WHERE river_id = ${river_id} AND kind = 111 + GROUP BY name, kind + </dc:statement> + <dc:elements> + <dc:if test="$uesg_exist>0"> + <floodmaps> + <dc:attribute name="factory" value="wmsfloodmapsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </floodmaps> + </dc:if> + </dc:elements> + </dc:context> + </bfg> + <land> + <dc:context> + <dc:statement> + SELECT count(*) as uesg_exist, name as name + FROM floodmaps + WHERE river_id = ${river_id} AND kind = 112 + GROUP BY name, kind + </dc:statement> + <dc:elements> + <dc:if test="$uesg_exist>0"> + <floodmaps> + <dc:attribute name="factory" value="wmsfloodmapsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </floodmaps> + </dc:if> + </dc:elements> + </dc:context> + </land> + </current> + <potentiel> + <bfg> + <dc:context> + <dc:statement> + SELECT count(*) as uesg_exist, name as name + FROM floodmaps + WHERE river_id = ${river_id} AND kind = 121 + GROUP BY name, kind + </dc:statement> + <dc:elements> + <dc:if test="$uesg_exist>0"> + <floodmaps> + <dc:attribute name="factory" value="wmsfloodmapsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </floodmaps> + </dc:if> + </dc:elements> + </dc:context> + </bfg> + <land> + <dc:context> + <dc:statement> + SELECT count(*) as uesg_exist, name as name + FROM floodmaps + WHERE river_id = ${river_id} AND kind = 122 + GROUP BY name, kind + </dc:statement> + <dc:elements> + <dc:if test="$uesg_exist>0"> + <floodmaps> + <dc:attribute name="factory" value="wmsfloodmapsfactory"/> + <dc:attribute name="ids" value="${river_id};${name}"/> + <dc:attribute name="name" value="${name}"/> + </floodmaps> + </dc:if> + </dc:elements> + </dc:context> + </land> + </potentiel> + </calculations> + </uesk> + </dc:macro> + <dc:macro name="flood-map-complete"> + <buildings> + <dc:call-macro name="flood-map-buildings"/> + </buildings> + <catchments> + <dc:call-macro name="flood-map-catchments"/> + </catchments> + <fixpoints> + <dc:call-macro name="flood-map-fixpoints"/> + </fixpoints> + <hws> + <dc:call-macro name="flood-map-hws"/> + </hws> + <hydrboundaries> + <dc:call-macro name="flood-map-hydr-boundaries"/> + <dc:call-macro name="flood-map-floodplain"/> + </hydrboundaries> + <kilometrage> + <riveraxis> + <dc:attribute name="factory" value="riveraxis"/> + <dc:attribute name="ids" value="${river_id}"/> + </riveraxis> + <dc:call-macro name="flood-map-km"/> + <dc:call-macro name="flood-map-qps"/> + </kilometrage> + <lines> + <dc:call-macro name="flood-map-lines"/> + </lines> + <dc:call-macro name="flood-map-uesk"/> + <gaugelocations> + <dc:call-macro name="flood-map-gaugelocations"/> + </gaugelocations> + <rastermap> + <background> + <dc:attribute name="factory" value="wmsbackground"/> + <dc:attribute name="ids" value="${river_id}"/> + </background> + </rastermap> + </dc:macro> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'minfo-heights')"> + <dc:call-macro name="minfo-heights"/> + <dc:macro name="minfo-heights"> + <bedheights> + <dc:call-macro name="bed-heights-single"/> + <dc:call-macro name="bed-heights-epoch"/> + </bedheights> + </dc:macro> + </dc:if> + <dc:if test="dc:contains($artifact-outs, 'minfo-heights-epoch')"> + <bedheights> + <dc:call-macro name="bed-heights-epoch"/> + </bedheights> + </dc:if> + <dc:macro name="bed-heights-single"> + <single> + <dc:context> + <dc:statement> + SELECT id AS bedh_id, + year AS bedh_year, + description AS bedh_descr + FROM bed_height_single WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <height> + <dc:attribute name="factory" value="bedheight"/> + <dc:attribute name="ids" value="bedheight-single-${bedh_id}-${bedh_year}"/> + <dc:attribute name="description" value="${bedh_descr}"/> + </height> + </dc:elements> + </dc:context> + </single> + </dc:macro> + <dc:macro name="bed-heights-epoch"> + <epoch> + <dc:context> + <dc:statement> + SELECT id AS bedh_id, + time_interval_id AS bedh_interval_id, + description AS bedh_descr + FROM bed_height_epoch WHERE river_id = ${river_id} + </dc:statement> + <dc:elements> + <height> + <dc:attribute name="factory" value="bedheight"/> + <dc:attribute name="ids" value="bedheight-epoch-${bedh_id}-${bedh_interval_id}"/> + <dc:attribute name="description" value="${bedh_descr}"/> + </height> + </dc:elements> + </dc:context> + </epoch> + </dc:macro> + </river> + </dc:elements> + </dc:context> + </dc:macro> + + <dc:choose> + <dc:comment> + User specific part + ------------------ + </dc:comment> + <dc:when test="dc:contains($parameters, 'user-id')"> + + + <old_calculations> + <dc:context connection="user"> + <dc:comment> + Get the user and collection-id. + </dc:comment> + <dc:statement> + SELECT u.id AS user_id, c.id AS collection_id, c.name as collection_name + FROM collections c JOIN users u ON c.user_id = u.id + WHERE u.gid = CAST(${user-id} AS uuid) + ORDER BY c.creation DESC + </dc:statement> + + <!-- OFFICIAL LINES --> + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')"> + <dc:comment comment=".wst -------------------------------"/> + <officiallines> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation, ardg.v as gaugy, arv.v as wqsingle + FROM master_artifacts m, artifact_data ardg, artifact_data arv + WHERE m.collection_id = ${collection_id} AND m.gid = CAST(${artifact-id} AS uuid) AND ardg.artifact_id = m.id AND ardg.k = 'ld_gaugename' AND arv.artifact_id = m.id AND arv.k = 'wq_single' + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context connection="system"> + <dc:statement> + SELECT ol.wst_id AS wstid, ol.wst_column_pos AS wstcolpos, ol.name AS olname, ol.value AS oval + FROM official_q_values ol + WHERE ol.value = CAST(${wqsingle} AS NUMERIC(10,2)) AND ol.gauge_name = ${gaugy} + </dc:statement> + <dc:elements> + <dc:element name="${olname}"> + <dc:attribute name="name" value="${olname}"/> + <dc:attribute name="ids" value="additionals-wstv-${wstcolpos}-${wstid}"/> + <dc:attribute name="factory" value="staticwkms"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </officiallines> + </dc:if> + <!-- END OFFICIAL LINES --> + + <dc:comment> + SHOW W-DIFFERENCES + </dc:comment> + + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section') or (dc:contains($artifact-outs, 'w_differences') or (dc:contains($artifact-outs, 'discharge_longitudinal_section')))"> + <differences> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description + FROM outs as o, facets as f, artifacts as a + WHERE f.name = 'w_differences' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id} + </dc:statement> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${aid}"/> + <dc:attribute name="ids" value="${aid}"/> + <dc:attribute name="out" value="w_differences"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </differences> + </dc:if> + + <dc:comment> + SHOW REFERENCE CURVE + </dc:comment> + + <dc:if test="dc:contains($artifact-outs, 'reference_curve')"> + <reference_curves> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description + FROM outs as o, facets as f, artifacts as a + WHERE f.name = 'reference_curve' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id} + </dc:statement> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${aid}"/> + <dc:attribute name="ids" value="${aid}"/> + <dc:attribute name="out" value="reference_curve"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </reference_curves> + </dc:if> + + <dc:comment> + SHOW COMPUTED DISCHARGE CURVES + </dc:comment> + + <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')"> + <computed_discharge_curves> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description + FROM outs as o, facets as f, artifacts as a + WHERE f.name = 'computed_discharge_curve.q' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id} + </dc:statement> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${aid}"/> + <dc:attribute name="ids" value="${aid}"/> + <dc:attribute name="out" value="computed_discharge_curve"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </computed_discharge_curves> + </dc:if> + + <dc:comment> + CROSS SECTION + </dc:comment> + + <dc:if test="dc:contains($artifact-outs, 'cross_section')"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'cross_section' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} + ORDER BY num ASC, name DESC + </dc:statement> + <longitudinal_section_columns> + <dc:attribute name="description" value="${river} ${a_creation}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="cross_section"/> + </dc:element> + </dc:elements> + </longitudinal_section_columns> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section') or (dc:contains($artifact-outs, 'discharge_longitudinal_section') or (dc:contains($artifact-outs, 'w_differences')))"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'longitudinal_section' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} + ORDER BY num ASC, name DESC + </dc:statement> + <longitudinal_section_columns> + <dc:attribute name="description" value="${river} ${a_creation}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="longitudinal_section"/> + </dc:element> + </dc:elements> + </longitudinal_section_columns> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'fix_longitudinal_section_curve' + </dc:statement> + <dc:elements> + <dc:context> + <!-- average und deviation ls_0 . ls_1 ...--> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} AND ( name LIKE 'fix_deviation_ls%' OR name LIKE 'fix_sector_average_ls%' OR name LIKE 'fix_analysis_events_ls%' OR name LIKE 'fix_reference_events_ls%' ) + ORDER BY num ASC, name DESC + </dc:statement> + <waterlevels> + <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="fixanalysis"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="fix_longitudinal_section_curve"/> + </dc:element> + </dc:elements> + </waterlevels> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'fix_deltawt_curve')"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'fix_deltawt_curve' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} and ( name LIKE 'fix_sector_average_dwt%' OR name LIKE 'fix_deviation_dwt%' OR name = 'fix_analysis_events_dwt' OR name = 'fix_reference_events_dwt' OR name = 'fix_analysis_periods_dwt' ) + ORDER BY num ASC, name DESC + </dc:statement> + <waterlevels> + <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="fixanalysis"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="fix_deltawt_curve"/> + </dc:element> + </dc:elements> + </waterlevels> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'fix_derivate_curve')"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'fix_derivate_curve' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} and name = 'fix_derivate' + ORDER BY num ASC, name DESC + </dc:statement> + <waterlevels> + <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="fixanalysis"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="fix_derivate_curve"/> + </dc:element> + </dc:elements> + </waterlevels> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'fix_wq_curve' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} and ( name LIKE 'fix_sector_average_wq%' OR name = 'fix_wq_curve' OR name LIKE 'fix_analysis_events_wq%' OR name LIKE 'fix_reference_events_wq%' ) + ORDER BY num ASC, name DESC + </dc:statement> + <waterlevels> + <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="fixanalysis"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="fix_wq_curve"/> + </dc:element> + </dc:elements> + </waterlevels> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:if test="dc:contains($artifact-outs, 'duration_curve')"> + <computed_discharge_curves> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description + FROM outs as o, facets as f, artifacts as a + WHERE (f.name = 'duration_curve.q' or f.name = 'duration_curve.w') and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id} + </dc:statement> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${aid}"/> + <dc:attribute name="ids" value="${aid}"/> + <dc:attribute name="out" value="duration_curve"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </computed_discharge_curves> + </dc:if> + <dc:comment> + WATERLEVELS - ONLY SHOW Ws + </dc:comment> + + <!-- TODO doesnt work nicely for fix/wq-diags. --> + <dc:if test="dc:contains($artifact-outs, 'waterlevels') or (dc:contains($artifact-outs, 'fix_wq_curve'))"> + <waterlevels> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + + <dc:context> + <dc:statement> + SELECT id AS out_id + FROM outs + WHERE artifact_id = ${a_id} AND name = 'longitudinal_section' + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT name AS facet_name, num as facet_num, description AS facet_description + FROM facets + WHERE out_id = ${out_id} and name = 'longitudinal_section.w' + ORDER BY num ASC, name DESC + </dc:statement> + <waterlevels> + <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="ids" value="${facet_num}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> + <dc:attribute name="out" value="longitudinal_section"/> + </dc:element> + </dc:elements> + </waterlevels> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </waterlevels> + </dc:if> + + <dc:comment> + SHOW FLOODMAPS + </dc:comment> + + <dc:if test="dc:contains($artifact-outs, 'floodmap') or dc:contains($artifact-outs, 'map')"> + <floodmap> + <dc:elements> + <dc:context> + <dc:statement> + SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation + FROM master_artifacts m + WHERE m.collection_id = ${collection_id} AND m.gid <> CAST(${artifact-id} AS uuid) + AND EXISTS ( + SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river}) + </dc:statement> + <dc:elements> + <dc:context> + <dc:statement> + SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description + FROM outs as o, facets as f, artifacts as a + WHERE f.name = 'floodmap.wsplgen' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id} + </dc:statement> + <dc:elements> + <dc:element name="${facet_name}"> + <dc:attribute name="description" value="${facet_description}"/> + <dc:attribute name="factory" value="winfo"/> + <dc:attribute name="artifact-id" value="${aid}"/> + <dc:attribute name="ids" value="${aid}"/> + <dc:attribute name="out" value="floodmap"/> + </dc:element> + </dc:elements> + </dc:context> + </dc:elements> + </dc:context> + </dc:elements> + </floodmap> + </dc:if> + + </dc:context> + </old_calculations> + + + <dc:comment> + Include System specific part when 'load-system' is in parameters. + ----------------------------------------------------------------- + </dc:comment> + <dc:choose> + <dc:when test="dc:contains($parameters,'load-system')"> + <dc:call-macro name="load-system"/> + </dc:when> + </dc:choose> + </dc:when> + + + <dc:comment> + Include System specific part only if no user ID is given. + --------------------------------------------------------- + </dc:comment> + <dc:otherwise> + <dc:call-macro name="load-system"/> + </dc:otherwise> + </dc:choose> +</datacage> +</dc:template>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/rest-server.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<rest-server> + <!-- The port which the ArtifactDatabase (ArtifactServer) will bind to. --> + <port>8181</port> + <listen>localhost</listen> +</rest-server>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/second-themes.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1578 @@ +<?xml version="1.0" encoding="UTF-8"?> +<themegroup name="second"> + <theme name="DischargeCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + <!-- concrete theme for historical discharge curves --> + <theme name="HistoricalDischargeCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + <theme name="HistoricalDischargeCurveQDiff"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 204" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + + <!-- Discharge Longitudinal Section --> + <theme name="LongitudinalSectionW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="bandwidth" type="double" display="Bandbreite" + default="0"/> + <field name="fillcolor" type="Color" display="Bandbreitenfarbe" + default="104, 104, 104"/> + <field name="transparency" type="int" default="30" display="Transparenz"/> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ2"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ5"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="51, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ10"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ20"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 0, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ25"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ50"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 153, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ100"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 128, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ200"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 128, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ500"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 128, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1000"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 128, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQRZ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 128, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HSQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 128" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MHQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MNQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 51, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_NQ"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 204, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQExtrem"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 255, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionPoints"> + <inherits> + <inherit from="LongitudinalSectionW" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" /> + <field name="showpoints" type="boolean" display="Punkte anzeigen" + default="true" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ2_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ5_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ10_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 204, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ20_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 153, 64" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ25_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 51, 64" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ50_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ100_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 10, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ200_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 64, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ500_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 64, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQ1000_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQRZ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 64, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HSQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 64" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MHQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 128, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MNQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 255, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_MQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 51, 178" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_NQ_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionW_HQExtrem_Points"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 64, 0" /> + </fields> + </theme> + + <!-- Longitudinal Section Q's --> + + <theme name="LongitudinalSectionQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 64, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ1"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ2"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ5"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 153, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ10"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ20"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 0, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ25"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 51, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ50"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 153" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ100"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 50, 51" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ200"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 255, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ500"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 102, 64" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQ1000"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 102, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQRZ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 102, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HSQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="253, 153, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MHQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="102, 0, 102" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MNQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 255" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_MQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="55, 51, 204" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_NQ"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="153, 204, 0" /> + </fields> + </theme> + + <theme name="LongitudinalSectionQ_HQExtrem"> + <inherits> + <inherit from="LongitudinalSectionQ" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 128, 0" /> + </fields> + </theme> + + <!-- Main Values --> + <theme name="MainValuesQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="200, 64, 0" /> + <field name="textcolor" type="Color" display="Farbe" + default="200, 0, 15" /> + <field name="showhorizontalline" type="boolean" + display="Horizontale Linie" default="true" /> + <field name="showverticalline" type="boolean" display="Vertikale Linie" + default="true" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <theme name="MainValuesW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="0, 0, 215" /> + <field name="textcolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="showhorizontalline" type="boolean" + display="Horizontale Linie" default="true" /> + <field name="showverticalline" type="boolean" display="Vertikale Linie" + default="true" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Computed Discharge Curves --> + <theme name="ComputedDischargeCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 153" /> + <field name="linesize" type="int" display="Liniendicke" + default="4" hints="h" /> + </fields> + </theme> + + <theme name="ComputedDischargeCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="200, 255, 15" /> + <field name="textcolor" type="Color" display="Farbe" + default="200, 0, 15" /> + </fields> + </theme> + + <theme name="ComputedDischargeCurveW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + <inherit from="Text" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="0, 215, 128" /> + <field name="textcolor" type="Color" display="Farbe" + default="0, 215, 0" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Cross Sections --> + <theme name="CrossSection"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,0,0" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + </fields> + </theme> + + <theme name="CrossSectionWaterLine"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255,0,153" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="showwidth" type="boolean" display="Breite anzeigen" + default="false" /> + <field name="showlevel" type="boolean" display="Wasserstand anzeigen" + default="true" /> + <field name="showlinelabel" type="boolean" default="true" + display="Beschriftung anzeigen" /> + <field name="showmiddleheight" type="boolean" + display="Wasserstand anzeigen" default="false" /> + </fields> + </theme> + + <theme name="Hyk"> + <inherits> + <inherit from="Text" /> + </inherits> + <fields> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <!-- Relative Points --> + <theme name="RelativePoint"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <!--fields> <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0"/> </fields --> + </theme> + + <!-- Duration Curves --> + <theme name="DurationCurveW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,51,204" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + <theme name="DurationCurveQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0,204,0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + </fields> + </theme> + + <!-- Differences --> + <theme name="Differences"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <!-- Reference Curves --> + <theme name="ReferenceCurveNormalized"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="ReferenceCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <!-- General --> + <theme name="WKms"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="WQKms"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="WQPoints"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" /> + <field name="showpoints" type="boolean" display="Punkte anzeigen" + default="true" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 200" /> + </fields> + </theme> + + <!-- Discharge Longitudinal Section --> + <theme name="DischargeLongitudinalSectionW"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + + <theme name="DischargeLongitudinalSectionC"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0 , 255" /> + </fields> + </theme> + + <theme name="DischargeLongitudinalSectionQ"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + + <!-- Annotations --> + <theme name="Annotations"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="Text" /> + <inherit from="AnnotationText" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="99, 99, 99" /> + </fields> + </theme> + + <!-- Manual Points --> + <theme name="ManualPoints"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="250, 255, 0" /> + <field name="font" type="Font" display="Schriftart" + default="arial" /> + <field name="textcolor" type="Color" display="Schriftfarbe" + default="0, 0, 0" /> + <field name="textsize" type="int" display="Schriftgröße" + default="10" /> + <field name="textstyle" type="Style" display="Schriftstil" + default="standard" /> + <field name="pointsize" type="int" display="Punktdicke" + default="2" hints="h" /> + <field name="backgroundcolor" type="Color" display="Texthintergrund" + default="55, 55, 55" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + <field name="showbackground" type="boolean" + display="Hintergrund anzeigen" default="false" /> + </fields> + </theme> + + <!-- Height Marks --> + <theme name="heightmarks_points"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="330, 33, 33" /> + </fields> + </theme> + + <!-- Areas --> + <theme name="Area"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="showarea" type="boolean" display="Show Area" + default="true"/> + </fields> + </theme> + + <!-- Map --> + <theme name="Floodmaps"> + <inherits> + <inherit from="Floodmap" /> + </inherits> + </theme> + + <theme name="Floodplains"> + <inherits> + <inherit from="Floodplain" /> + </inherits> + </theme> + + <theme name="WSPLGEN"> + <inherits> + <inherit from="WSPLGENS" /> + </inherits> + </theme> + + <theme name="RiverAxis"> + <inherits> + <inherit from="RiverAxes" /> + </inherits> + </theme> + + <theme name="Kms"> + <inherits> + <inherit from="Km" /> + </inherits> + </theme> + + + <theme name="Fixpoints"> + <inherits> + <inherit from="Fixpoint" /> + </inherits> + </theme> + + + <theme name="GaugeLocation"> + <inherits> + <inherit from="GaugeLocations" /> + </inherits> + </theme> + + + <theme name="Qps"> + <inherits> + <inherit from="Qp" /> + </inherits> + </theme> + + <theme name="Hws"> + <inherits> + <inherit from="Hw" /> + </inherits> + </theme> + + <theme name="Catchment"> + <inherits> + <inherit from="Catchments" /> + </inherits> + </theme> + + <theme name="FloodmapLines"> + <inherits> + <inherit from="FloodmapLine" /> + </inherits> + </theme> + + <theme name="Buildings"> + <inherits> + <inherit from="Building" /> + </inherits> + </theme> + + <theme name="HydrBoundariesLines"> + <inherits> + <inherit from="HydrBoundariesLine" /> + </inherits> + </theme> + + <theme name="HydrBoundariesPolys"> + <inherits> + <inherit from="HydrBoundariesPoly" /> + </inherits> + </theme> + + <!-- MIDDLE BED HEIGHT --> + <theme name="MiddleBedHeightSingle"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="128, 128, 128" /> + </fields> + </theme> + + <theme name="MiddleBedHeightEpoch"> + <inherits> + <inherit from="FlowVelocityVMainChannel" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 0, 102" /> + </fields> + </theme> + + + <!-- Bed Quality --> + <theme name="PorosityTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="100, 100, 100" /> + </fields> + </theme> + + <theme name="PorositySubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="100, 100, 100" /> + </fields> + </theme> + + <theme name="DensityTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#990000" /> + </fields> + </theme> + + <theme name="DensitySubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#990000" /> + </fields> + </theme> + + <theme name="BedDiameterTopLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#FF4444" /> + </fields> + </theme> + + <theme name="BedDiameterSubLayer"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#FF4444" /> + </fields> + </theme> + + <theme name="BedLoadDiameter"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="#33FF11" /> + </fields> + </theme> + + + <!-- FLOW VELOCITY --> + <theme name="FlowVelocityVMainChannel"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 0, 204" /> + </fields> + </theme> + + <theme name="FlowVelocityVTotalChannel"> + <inherits> + <inherit from="FlowVelocityVMainChannel" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="64, 0, 102" /> + </fields> + </theme> + + <theme name="FlowVelocityTau"> + <inherits> + <inherit from="HiddenColorLines" /> + <inherit from="MinMaxPoints" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 204, 0" /> + </fields> + </theme> + + + <!-- SQ Relation --> + <theme name="SQMeasurements"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" hidden="true" /> + <field name="pointcolor" type="Color" default="0, 99, 255" /> + </fields> + </theme> + + <theme name="SQOutliers"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="false" hidden="true" /> + <field name="pointcolor" type="Color" default="0, 99, 0" /> + </fields> + </theme> + + <theme name="SQCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="#000000" /> + <field name="linesize" type="int" default="3" /> + </fields> + </theme> + + <theme name="FixingWQCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 27, 162" /> + </fields> + </theme> + + <theme name="FixingDerivedCurve"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 27, 162" /> + <field name="showpoints" type="boolean" display="Datenpunkte anzeigen" + default="false" hints="h" hidden="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5" hints="h" hidden="true" /> + </fields> + </theme> + + <theme name="FixingSectorAverageWQ0"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="false" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 128, 128" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ1"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 64, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ2"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="2" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="255, 0, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + <theme name="FixingSectorAverageWQ3"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="255, 0, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingAnalysisEventsWQ"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 255, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingReferenceEvents"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlines" type="boolean" default="false" + hidden="true" /> + <field name="showlinelabel" type="boolean" default="false" + hidden="true" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" hidden="true" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hidden="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="4" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 80, 255" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="true"/> + </fields> + </theme> + + <theme name="FixingOutliers"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingDeltaWtAverage0"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 128, 128" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage1"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="128, 0, 255" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage2"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 128, 255" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + <theme name="FixingDeltaWtAverage3"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + + + <theme name="FixingDeltaWtAnalysis"> + <inherits> + <inherit from="ColorPoints" /> + </inherits> + <fields> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="showlines" type="boolean" default="false" /> + <field name="pointsize" type="int" display="Punktdicke" + default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 255, 0" /> + <field name="textorientation" type="boolean" default="true" display="Text horizontal"/> + </fields> + </theme> + + <theme name="FixingLSAverage0"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 128, 64" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage1"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 64, 255" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage2"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="255, 64, 255" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixingLSAverage3"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="255, 0, 64" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + + <theme name="FixingSectorDeviationLS0"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="0, 128, 64" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS1"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="64, 0, 255" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS2"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="255, 64, 255" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixingSectorDeviationLS3"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="255, 64, 0" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixLSDeviation"> + <inherits> + <inherit from="Areas" /> + </inherits> + <fields> + <field name="fillcolor" type="Color" display="Fuellfarbe" + default="200, 200, 200" /> + <field name="transparent" type="boolean" display="Transparenz" + default="true" /> + </fields> + </theme> + <theme name="FixLSAnalysis"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="0, 0, 255" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixLSReference"> + <inherits> + <inherit from="HiddenColorLines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" default="160, 80, 160" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + </fields> + </theme> + <theme name="FixDeltaWtDeviation"> + <inherits> + <inherit from="Areas"/> + </inherits> + <fields> + <field name="transparency" type="int" default="30" display="Transparenz"/> + <field name="backgroundcolor" type="Color" default="0, 0, 0" display="Füllfarbe"/> + </fields> + </theme> + <theme name="FixingDeltaWtAnalysisPeriods"> + <inherits> + <inherit from="Areas"/> + </inherits> + <fields> + <field name="transparency" type="int" default="90" display="Transparenz"/> + </fields> + </theme> + + <theme name="QSectors"> + <fields> + <field name="linecolor" type="Color" default="32, 27, 162" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" hidden="true" /> + <field name="linesize" type="int" display="Liniendicke" + default="2" hidden="true" /> + <field name="labelfontface" type="Font" + display="Beschriftung: Schriftart" default="arial" /> + <field name="labelfontcolor" type="Color" + display="Beschriftung: Schriftfarbe" default="0, 0, 0" /> + <field name="labelfontsize" type="int" + display="Beschriftung: Schriftgröße" default="9" /> + <field name="labelfontstyle" type="Style" + display="Beschriftung: Schriftstil" default="standard" /> + </fields> + </theme> + +</themegroup>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/seddb-db.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<seddb-database> + <!-- This is the default SedDB db configuration. --> + <user>sedb</user> + <password>sedb</password> + <dialect>org.hibernate.dialect.PostgreSQLDialect</dialect> + <driver>org.postgresql.Driver</driver> + <url>jdbc:postgresql://localhost:5432/seddb</url> +</seddb-database>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/themes.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,261 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE themes [ + <!ENTITY default-themes SYSTEM "conf/default-themes.xml"> + <!ENTITY second-themes SYSTEM "conf/second-themes.xml"> + <!ENTITY virtual-themes SYSTEM "conf/virtual-themes.xml"> +]> +<themes> + &default-themes; + &second-themes; + &virtual-themes; + + <!-- Mappings are following now. A mapping maps between a name of a facet + and a theme. Always the first matching mapping is taken, so consider putting + most specific mappings on top of the list. --> + <mappings> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ1)(\D.*)*" to="LongitudinalSectionW_HQ1_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ2)(\D.*)*" to="LongitudinalSectionW_HQ2_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ5)(\D.*)*" to="LongitudinalSectionW_HQ5_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ10)(\D.*)*" to="LongitudinalSectionW_HQ10_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ20)(\D.*)*" to="LongitudinalSectionW_HQ20_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ25)(\D.*)*" to="LongitudinalSectionW_HQ25_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ50)(\D.*)*" to="LongitudinalSectionW_HQ50_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ100)(\D.*)*" to="LongitudinalSectionW_HQ100_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ200)(\D.*)*" to="LongitudinalSectionW_HQ200_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ500)(\D.*)*" to="LongitudinalSectionW_HQ500_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQ1000)(\D.*)*" to="LongitudinalSectionW_HQ1000_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQExtrem)(\D.*)*" to="LongitudinalSectionW_HQExtrem_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HQRZ)(\D.*)*" to="LongitudinalSectionW_HQRZ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(HSQ)(\D.*)*" to="LongitudinalSectionW_HSQ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(MHQ)(\D.*)*" to="LongitudinalSectionW_MHQ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(MNQ)(\D.*)*" to="LongitudinalSectionW_MNQ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(MQ)(\D.*)*" to="LongitudinalSectionW_MQ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + pattern=".*(NQ)(\D.*)*" to="LongitudinalSectionW_NQ_Points" /> + <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" + to="LongitudinalSectionPoints" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ1)(\D.*)*" + to="LongitudinalSectionW_HQ1" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ2)(\D.*)*" + to="LongitudinalSectionW_HQ2" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ5)(\D.*)*" + to="LongitudinalSectionW_HQ5" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ10)(\D.*)*" + to="LongitudinalSectionW_HQ10" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ20)(\D.*)*" + to="LongitudinalSectionW_HQ20" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ25)(\D.*)*" + to="LongitudinalSectionW_HQ25" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ50)(\D.*)*" + to="LongitudinalSectionW_HQ50" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ100)(\D.*)*" + to="LongitudinalSectionW_HQ100" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ200)(\D.*)*" + to="LongitudinalSectionW_HQ200" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ500)(\D.*)*" + to="LongitudinalSectionW_HQ500" /> + <mapping from="longitudinal_section.w" pattern=".*(HQ1000)(\D.*)*" + to="LongitudinalSectionW_HQ1000" /> + <mapping from="longitudinal_section.w" pattern=".*(HQExtrem)(\D.*)*" + to="LongitudinalSectionW_HQExtrem" /> + <mapping from="longitudinal_section.w" pattern=".*(HQRZ)(\D.*)*" + to="LongitudinalSectionW_HQRZ" /> + <mapping from="longitudinal_section.w" pattern=".*(HSQ)(\D.*)*" + to="LongitudinalSectionW_HSQ" /> + <mapping from="longitudinal_section.w" pattern=".*(MHQ)(\D.*)*" + to="LongitudinalSectionW_MHQ" /> + <mapping from="longitudinal_section.w" pattern=".*(MNQ)(\D.*)*" + to="LongitudinalSectionW_MNQ" /> + <mapping from="longitudinal_section.w" pattern=".*(MQ)(\D.*)*" + to="LongitudinalSectionW_MQ" /> + <mapping from="longitudinal_section.w" pattern=".*(NQ)(\D.*)*" + to="LongitudinalSectionW_NQ" /> + <mapping from="longitudinal_section.w" to="LongitudinalSectionW" /> + + <mapping from="longitudinal_section.q" pattern="(HQ1)(\D.*)*" + to="LongitudinalSectionQ_HQ1" /> + <mapping from="longitudinal_section.q" pattern="(HQ2)(\D.*)*" + to="LongitudinalSectionQ_HQ2" /> + <mapping from="longitudinal_section.q" pattern="(HQ5)(\D.*)*" + to="LongitudinalSectionQ_HQ5" /> + <mapping from="longitudinal_section.q" pattern="(HQ10)(\D.*)*" + to="LongitudinalSectionQ_HQ10" /> + <mapping from="longitudinal_section.q" pattern="(HQ20)(\D.*)*" + to="LongitudinalSectionQ_HQ20" /> + <mapping from="longitudinal_section.q" pattern="(HQ25)(\D.*)*" + to="LongitudinalSectionQ_HQ25" /> + <mapping from="longitudinal_section.q" pattern="(HQ50)(\D.*)*" + to="LongitudinalSectionQ_HQ50" /> + <mapping from="longitudinal_section.q" pattern="(HQ100)(\D.*)*" + to="LongitudinalSectionQ_HQ100" /> + <mapping from="longitudinal_section.q" pattern="(HQ200)(\D.*)*" + to="LongitudinalSectionQ_HQ200" /> + <mapping from="longitudinal_section.q" pattern="(HQ500)(\D.*)*" + to="LongitudinalSectionQ_HQ500" /> + <mapping from="longitudinal_section.q" pattern="(HQ1000)(\D.*)*" + to="LongitudinalSectionQ_HQ1000" /> + <mapping from="longitudinal_section.q" pattern="(HQExtrem)(\D.*)*" + to="LongitudinalSectionQ_HQExtrem" /> + <mapping from="longitudinal_section.q" pattern="(HQRZ)(\D.*)*" + to="LongitudinalSectionQ_HQRZ" /> + <mapping from="longitudinal_section.q" pattern="(HSQ)(\D.*)*" + to="LongitudinalSectionQ_HSQ" /> + <mapping from="longitudinal_section.q" pattern="(MHQ)(\D.*)*" + to="LongitudinalSectionQ_MHQ" /> + <mapping from="longitudinal_section.q" pattern="(MNQ)(\D.*)*" + to="LongitudinalSectionQ_MNQ" /> + <mapping from="longitudinal_section.q" pattern="(MQ)(\D.*)*" + to="LongitudinalSectionQ_MQ" /> + <mapping from="longitudinal_section.q" pattern="(NQ)(\D.*)*" + to="LongitudinalSectionQ_NQ" /> + <mapping from="longitudinal_section.q" to="LongitudinalSectionQ" /> + + <mapping from="discharge_curve.curve" to="DischargeCurve" /> + <mapping from="historical_discharge.historicalq" to="HistoricalDischargeCurveQ" /> + <mapping from="historical_discharge.historicalq.diff" to="HistoricalDischargeCurveQDiff" /> + <mapping from="cross_section" to="CrossSection" /> + <mapping from="cross_section_water_line" to="CrossSectionWaterLine" /> + <mapping from="computed_discharge_curve.q" to="ComputedDischargeCurve" /> + <mapping from="duration_curve.w" to="DurationCurveW" /> + <mapping from="duration_curve.q" to="DurationCurveQ" /> + <mapping from="discharge_longitudinal_section.w" to="DischargeLongitudinalSectionW" /> + <mapping from="discharge_longitudinal_section.c" to="DischargeLongitudinalSectionC" /> + <mapping from="discharge_longitudinal_section.q" to="DischargeLongitudinalSectionQ" /> + <mapping from="computed_discharge_curve.mainvalues.q" to="MainValuesQ" /> + <mapping from="computed_discharge_curve.mainvalues.w" to="MainValuesW" /> + <mapping from="duration_curve.mainvalues.q" to="MainValuesQ" /> + <mapping from="mainvalues.q" to="MainValuesQ" /> + <mapping from="mainvalues.w" to="MainValuesW" /> + <mapping from="longitudinal_section.annotations" to="Annotations" /> + <mapping from="w_differences" to="Differences" /> + <mapping from="floodmap.wsplgen" to="WSPLGEN" /> + <mapping from="floodmap.riveraxis" to="RiverAxis" /> + <mapping from="floodmap.kms" to="Kms" /> + <mapping from="floodmap.qps" to="Qps" /> + <mapping from="floodmap.hws" to="Hws" /> + <mapping from="floodmap.hydr_boundaries" to="HydrBoundariesLines" /> + <mapping from="floodmap.hydr_boundaries_poly" to="HydrBoundariesPolys" /> + <mapping from="floodmap.catchment" to="Catchment" /> + <mapping from="floodmap.floodplain" to="Floodplains" /> + <mapping from="floodmap.lines" to="FloodmapLines" /> + <mapping from="floodmap.buildings" to="Buildings" /> + <mapping from="floodmap.fixpoints" to="Fixpoints" /> + <mapping from="floodmap.floodmaps" to="Floodmaps" /> + <mapping from="floodmap.gauge_location" to="GaugeLocation" /> + <mapping from="other.wq" to="WQPoints" /> + <mapping from="other.wkms" to="WKms" /> + <mapping from="other.wqkms" to="WQKms" /> + <mapping from="other.wqkms.w" to="WQKms" /> + <mapping from="other.wqkms.q" to="WQKms" /> + <mapping from="heightmarks_points" to="heightmarks_points" /> + <mapping from="area" to="Area" /> + <mapping from="cross_section.area" to="Area" /> + <mapping from="hyk" to="Hyk" /> + <mapping from="longitudinal_section.area" to="Area" /> + <mapping from="longitudinal_section.manualpoints" to="ManualPoints" /> + <mapping from="cross_section.manualpoints" to="ManualPoints" /> + <mapping from="cross_section.manualline" to="CrossSectionWaterLine" /> + <mapping from="computed_discharge_curve.manualpoints" to="ManualPoints" /> + <mapping from="duration_curve.manualpoints" to="ManualPoints" /> + <mapping from="wdifferences.manualpoints" to="ManualPoints" /> + <mapping from="discharge_longitudinal_section.manualpoints" + to="ManualPoints" /> + <mapping from="discharge_curve.manualpoints" to="ManualPoints" /> + <mapping from="reference_curve.manualpoints" to="ManualPoints" /> + <mapping from="reference_curve_normalized.manualpoints" to="ManualPoints" /> + <mapping from="historical_discharge.manualpoints" to="ManualPoints" /> + <mapping from="manualpoints" to="ManualPoints" /> + <mapping from="reference_curve" to="ReferenceCurve" /> + <mapping from="reference_curve_normalized" to="ReferenceCurveNormalized" /> + <mapping from="flow_velocity.totalchannel" to="FlowVelocityVTotalChannel" /> + <mapping from="flow_velocity.mainchannel" to="FlowVelocityVMainChannel" /> + <mapping from="flow_velocity.tau" to="FlowVelocityTau" /> + <mapping from="bedheight_middle.single" to="MiddleBedHeightSingle" /> + <mapping from="bedheight_middle.epoch" to="MiddleBedHeightEpoch" /> + <mapping from="bed_longitudinal_section.porosity_toplayer" to="PorosityTopLayer" /> + <mapping from="bed_longitudinal_section.porosity_sublayer" to="PorositySubLayer" /> + <mapping from="bed_longitudinal_section.sediment_density_toplayer" to="DensityTopLayer" /> + <mapping from="bed_longitudinal_section.sediment_density_sublayer" to="DensitySublayer" /> + <mapping from="bed_longitudinal_section.bed_diameter_toplayer" to="BedDiameterTopLayer" /> + <mapping from="bed_longitudinal_section.bed_diameter_sublayer" to="BedDiameterSubLayer" /> + <mapping from="bed_longitudinal_section.bedload_diameter" to="BedLoadDiameter" /> + <mapping from="relativepoint" to="RelativePoint" /> + <mapping from="sq_a_measurement" to="SQMeasurements" /> + <mapping from="sq_a_outlier" to="SQOutliers" /> + <mapping from="sq_a_curve" to="SQCurve" /> + <mapping from="sq_a_outlier_curve" to="SQCurve" /> + <mapping from="sq_a_outlier_measurement" to="SQMeasurements" /> + <mapping from="sq_b_measurement" to="SQMeasurements" /> + <mapping from="sq_b_outlier" to="SQOutliers" /> + <mapping from="sq_b_curve" to="SQCurve" /> + <mapping from="sq_b_outlier_curve" to="SQCurve" /> + <mapping from="sq_b_outlier_measurement" to="SQMeasurements" /> + <mapping from="sq_c_measurement" to="SQMeasurements" /> + <mapping from="sq_c_outlier" to="SQOutliers" /> + <mapping from="sq_c_curve" to="SQCurve" /> + <mapping from="sq_c_outlier_curve" to="SQCurve" /> + <mapping from="sq_c_outlier_measurement" to="SQMeasurements" /> + <mapping from="sq_d_measurement" to="SQMeasurements" /> + <mapping from="sq_d_outlier" to="SQOutliers" /> + <mapping from="sq_d_curve" to="SQCurve" /> + <mapping from="sq_d_outlier_curve" to="SQCurve" /> + <mapping from="sq_d_outlier_measurement" to="SQMeasurements" /> + <mapping from="sq_e_measurement" to="SQMeasurements" /> + <mapping from="sq_e_outlier" to="SQOutliers" /> + <mapping from="sq_e_curve" to="SQCurve" /> + <mapping from="sq_e_outlier_curve" to="SQCurve" /> + <mapping from="sq_e_outlier_measurement" to="SQMeasurements" /> + <mapping from="sq_f_measurement" to="SQMeasurements" /> + <mapping from="sq_f_outlier" to="SQOutliers" /> + <mapping from="sq_f_curve" to="SQCurve" /> + <mapping from="sq_f_outlier_curve" to="SQCurve" /> + <mapping from="sq_f_outlier_measurement" to="SQMeasurements" /> + <mapping from="fix_sector_average_wq_0" to="FixingSectorAverageWQ0" /> + <mapping from="fix_sector_average_wq_1" to="FixingSectorAverageWQ1" /> + <mapping from="fix_sector_average_wq_2" to="FixingSectorAverageWQ2" /> + <mapping from="fix_sector_average_wq_3" to="FixingSectorAverageWQ3" /> + <mapping from="fix_analysis_events_wq" to="FixingAnalysisEventsWQ" /> + <mapping from="fix_outlier" to="FixingOutlier" /> + <mapping from="fix_wq_curve" to="FixingWQCurve" /> + <mapping from="fix_reference_events_wq" to="FixingReferenceEvents" /> + <mapping from="fix_sector_average_dwt_0" to="FixingDeltaWtAverage0" /> + <mapping from="fix_sector_average_dwt_1" to="FixingDeltaWtAverage1" /> + <mapping from="fix_sector_average_dwt_2" to="FixingDeltaWtAverage2" /> + <mapping from="fix_sector_average_dwt_3" to="FixingDeltaWtAverage3" /> + <mapping from="fix_analysis_events_dwt" to="FixingDeltaWtAnalysis" /> + <mapping from="fix_analysis_periods_dwt" to="FixingDeltaWtAnalysisPeriods" /> + <mapping from="fix_reference_events_dwt" to="FixingReferenceEvents" /> + <mapping from="fix_sector_average_ls_deviation_0" to="FixingSectorDeviationLS0" /> + <mapping from="fix_sector_average_ls_deviation_1" to="FixingSectorDeviationLS1" /> + <mapping from="fix_sector_average_ls_deviation_2" to="FixingSectorDeviationLS2" /> + <mapping from="fix_sector_average_ls_deviation_3" to="FixingSectorDeviationLS3" /> + <mapping from="fix_sector_average_ls_0" to="FixingLSAverage0" /> + <mapping from="fix_sector_average_ls_1" to="FixingLSAverage1" /> + <mapping from="fix_sector_average_ls_2" to="FixingLSAverage2" /> + <mapping from="fix_sector_average_ls_3" to="FixingLSAverage3" /> + <mapping from="fix_deviation_ls" to="FixLSDeviation" /> + <mapping from="fix_deviation_dwt" to="FixDeltaWtDeviation" /> + <mapping from="fix_analysis_events_ls" to="FixLSAnalysis" /> + <mapping from="fix_reference_events_ls" to="FixLSReference" /> + <mapping from="fix_derivate" to="FixingDerivedCurve" /> + <mapping from="fix_derivate.manualpoints" to="ManualPoints" /> + <mapping from="qsectors" to="QSectors" /> + </mappings> +</themes>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/conf/virtual-themes.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,299 @@ +<?xml version="1.0" encoding="UTF-8"?> +<themegroup name="virtual"> + <!-- Virtual themes are following now! DO NOT USE VIRTUAL THEMES FOR + FACETS! Please implement concrete themes! --> + <theme name="Lines" type="virtual"> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="true" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" /> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="false" hints="h" /> + <field name="labelfontface" type="Font" + display="Beschriftung: Schriftart" default="arial" /> + <field name="labelfontcolor" type="Color" + display="Beschriftung: Schriftfarbe" default="0, 0, 0" /> + <field name="labelfontsize" type="int" + display="Beschriftung: Schriftgröße" default="10" /> + <field name="labelfontstyle" type="Style" + display="Beschriftung: Schriftstil" default="standard" /> + <field name="labelbgcolor" type="Color" + display="Beschriftung: Hintergrundfarbe" default="0, 0, 0" /> + <field name="labelshowbg" type="boolean" + display="Beschriftung: Hintergrund füllen" default="false" /> + <!--orientation? --> + </fields> + </theme> + + <theme name="Points" type="virtual"> + <fields> + <field name="showlinelabel" type="boolean" + display="Linienbeschriftung anzeigen" default="false" /> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> + <field name="showlines" type="boolean" default="false" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" /> + <field name="showpoints" type="boolean" display="Punkte anzeigen" + default="true" /> + <field name="textorientation" type="boolean" display="Text horizontal" + default="true"/> + <field name="labelfontface" type="Font" default="Arial" + display="Beschriftung: Schriftart" /> + <field name="labelfontcolor" type="Color" default="Color.BLACK" + display="Beschriftung: Schriftfarbe" /> + <field name="labelfontsize" type="int" + display="Beschriftung: Schriftgröße" default="10" /> + <field name="labelshowbg" type="boolean" default="false" + display="Beschriftung: Hintergrund anzeigen" /> + <field name="labelbgcolor" type="Color" default="Color.WHITE" + display="Beschriftung: Hintergrundfarbe" /> + </fields> + </theme> + + <theme name="ColorLines" type="virtual"> + <inherits> + <inherit from="Lines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="Color.BLACK" /> + </fields> + </theme> + + <theme name="HiddenColorLines" type="virtual"> + <inherits> + <inherit from="ColorLines" /> + </inherits> + <fields> + <field name="showlines" type="boolean" display="Linie anzeigen" + default="true" hints="h" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="linetype" type="Dash" display="Linienart" + default="10" hints="h" /> + <field name="showpoints" type="boolean" display="Datenpunkte anzeigen" + default="false" hints="h" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5" hints="h" /> + </fields> + </theme> + + <theme name="ColorPoints" type="virtual"> + <inherits> + <inherit from="Points" /> + </inherits> + <fields> + <field name="showpoints" type="boolean" display="Datenpunkte anzeigen" + default="true" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5" /> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="Color.BLACK" /> + </fields> + </theme> + + <theme name="MinMaxPoints" type="virtual"> + <fields> + <field name="showminimum" type="boolean" display="Minimum anzeigen" + default="false" hints="h" /> + <field name="showmaximum" type="boolean" display="Minimum anzeigen" + default="false" hints="h" /> + </fields> + </theme> + + <theme name="Text" type="virtual"> + <fields> + <field name="font" type="Font" display="Schriftart" + default="arial" /> + <field name="textcolor" type="Color" display="Schriftfarbe" + default="0, 0, 0" /> + <field name="textsize" type="int" display="Schriftgröße" + default="10" /> + <field name="textstyle" type="Style" display="Schriftstil" + default="standard" /> + </fields> + </theme> + + <theme name="AnnotationText" type="virtual"> + <fields> + <field name="backgroundcolor" type="Color" display="Texthintergrund" + default="255, 255, 255" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="false" /> + <field name="showbackground" type="boolean" + display="Hintergrund anzeigen" default="false" /> + </fields> + </theme> + + <!-- Area relevant theme(s) --> + <theme name="Areas"> + <fields> + <field name="backgroundcolor" type="Color" display="Füllfarbe" + default="0, 100, 0" /> + <!-- <field name="showbackground" type="boolean" + display="Hintergrund anzeigen" default="true" hidden="true" /> //--> + <!-- <field name="showborder" type="boolean" + display="Flaechebegrenzungslinie anzeigen" default="false" /> //--> + <field name="transparency" type="int" default="50" display="Transparenz" /> + </fields> + </theme> + + + <!-- MAP relevant themes --> + <theme name="WSPLGENS" type="virtual"> + <fields> + <field name="wsplgen_cat1" type="Color" display="Hintergrund" + default="178, 201, 215" /> + <field name="wsplgen_cat2" type="Color" display="Hintergrund" + default="111, 147, 170" /> + <field name="wsplgen_cat3" type="Color" display="Hintergrund" + default="66, 111, 139" /> + <field name="wsplgen_cat4" type="Color" display="Hintergrund" + default="33, 79, 108" /> + <field name="wsplgen_cat5" type="Color" display="Hintergrund" + default="2, 27, 42" /> + </fields> + </theme> + + <theme name="RiverAxes" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 205" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + </fields> + </theme> + + <theme name="Km" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="5" hints="h" /> + <field name="textcolor" type="Color" display="Schriftfarbe" + default="0, 0, 0" /> + <field name="textsize" type="int" display="Schriftgröße" + default="10" /> + <field name="symbol" type="Symbol" display="Symbol" + default="square" /> + </fields> + </theme> + + <theme name="Fixpoint" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + <field name="symbol" type="Symbol" display="Symbol" + default="point" /> + </fields> + </theme> + + <theme name="Floodmap" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="backgroundcolor" type="Color" display="Hintergrund" + default="140, 200, 130" /> + </fields> + </theme> + + <theme name="GaugeLocations" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="symbol" type="Symbol" display="Symbol" + default="point" /> + </fields> + </theme> + + <theme name="Qp" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 255" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + </fields> + </theme> + + <theme name="Hw" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + </fields> + </theme> + + <theme name="Catchments" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="backgroundcolor" type="Color" display="Hintergrund" + default="140, 200, 130" /> + </fields> + </theme> + + <theme name="Floodplain" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="0, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="1" hints="h" /> + <field name="backgroundcolor" type="Color" display="Hintergrund" + default="140, 200, 130" /> + </fields> + </theme> + + <theme name="FloodmapLine" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="140, 200, 130" /> + <field name="linesize" type="int" display="Liniendicke" + default="3" hints="h" /> + </fields> + </theme> + + <theme name="Building" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="5" hints="h" /> + </fields> + </theme> + + <theme name="HydrBoundariesLine" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="5" hints="h" /> + </fields> + </theme> + + <theme name="HydrBoundariesPoly" type="virtual"> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="255, 0, 0" /> + <field name="linesize" type="int" display="Liniendicke" + default="5" hints="h" /> + <field name="backgroundcolor" type="Color" display="Hintergrund" + default="140, 200, 130" /> + </fields> + </theme> + +</themegroup>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/Makefile Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,3492 @@ +# Copyright 2004 Chris Monson (shiblon@gmail.com) +# Latest version available at http://www.bouncingchairs.net/oss +# +# This file is part of ``Chris Monson's Free Software''. +# +# ``Chris Monson's Free Software'' is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, Version 2. +# +# ``Chris Monson's Free Software'' is distributed in the hope that it will +# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with ``Chris Monson's Free Software''; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# It is also available on the web at http://www.gnu.org/copyleft/gpl.html +# +# Note that using this makefile to build your documents does NOT place them +# under the GPL unless you, the author, specifically do so. In other words, +# I, Chris Monson, the copyright holder and author of this makefile, +# consider it impossible to ``link'' to this makefile in any way covered by +# the GPL. +# +# TO OBTAIN INSTRUCTIONS FOR USING THIS FILE, RUN: +# make help +# +fileinfo := LaTeX Makefile +author := Chris Monson +version := 2.2.0-rc1 +# +# Note that the user-global version is imported *after* the source directory, +# so that you can use stuff like ?= to get proper override behavior. +.PHONY: Makefile GNUmakefile Makefile.ini $(HOME)/.latex-makefile/Makefile.ini +-include Makefile.ini +-include $(HOME)/.latex-makefile/Makefile.ini +# +# This can be pdflatex or latex - you can change this by adding the following line to your Makefile.ini: +# BUILD_STRATEGY := latex +BUILD_STRATEGY ?= pdflatex +# +# Sets LC_ALL=C, by default, so that the locale-aware tools, like sort, be +# # immune to changes to the locale in the user environment. +export LC_ALL ?= C +# +# +# If you specify sources here, all other files with the same suffix +# will be treated as if they were _include_ files. +#onlysources.tex ?= main.tex +#onlysources.tex.sh ?= +#onlysources.tex.pl ?= +#onlysources.tex.py ?= +#onlysources.rst ?= +#onlysources.fig ?= +#onlysources.gpi ?= +#onlysources.dot ?= +#onlysources.xvg ?= +#onlysources.svg ?= +#onlysources.eps.gz ?= +#onlysources.eps ?= +# +# If you list files here, they will be treated as _include_ files +#includes.tex ?= file1.tex file2.tex +#includes.tex.sh ?= +#includes.tex.pl ?= +#includes.tex.py ?= +#includes.rst ?= +#includes.fig ?= +#includes.gpi ?= +#includes.dot ?= +#includes.xvg ?= +#includes.svg ?= +#includes.eps.gz ?= +#includes.eps ?= +# +# If you list files or wildcards here, they will *not* be cleaned - default is +# to allow everything to be cleaned. +#neverclean ?= *.pdf +# +# Alternatively (recommended), you can add those lines to a Makefile.ini file +# and it will get picked up automatically without your having to edit this +# Makefile. +# +# KNOWN ISSUES: +# * The following occurs: +# file with: \usepackage{named}\bibliographystyle{named} +# Compile +# change to: \usepackage{apalike}\bibliographystyle{apalike} +# Compile again -- BARF! +# +# The workaround: make clean-nographics; make +# +# Note that we may not be able to fix this. LaTeX itself barfs +# on this, not the makefile. The very first invocation of LaTeX +# (when something like this has happened) reads the existing .aux +# file and discovers invalid commands like \citeauthoryear that +# are only valid in the package that was just removed. It then +# tries to parse them and explodes. It's not at all clear to me +# how to fix this. I tried removing the .aux files on the first +# run of LaTeX, but that necessarily requires more subsequent +# rebuilds on common edits. There does not appear to be a +# graceful solution to this issue. +# +# CHANGES: +# Chris Monson (2010-04-08): +# * Bumped version to 2.2.0-rc1 +# * Added back in the rst_style_file stuff that got broken when switching +# rst -> tex to use the script mechanism +# Chris Monson (2010-03-23): +# * Bumped version to 2.2.0-beta8 +# * Work on issue 76: bad backtick escape for some sed versions, failure +# to clear out the hold buffer when outputting MISSING comment. +# - Backed out 2>&1 to &> (doesn't work in sh) +# - Backed out using . to source variables +# Chris Monson (2010-03-22): +# * Bumped version to 2.2.0-beta7 +# * Issue 72: Fix latex/bibtex invocation order for annotated bib styles +# * Fixed informational output to reflect which LaTeX run we're on +# * Fixed graphic detection to include graphics that are already there in +# .d files +# * Tightened up the .d file output to only make .d depend on graphic +# *source* files. This means that building foo.d no longer +# builds all of the graphics files on which foo.tex depends. +# Had to use .SECONDEXPANSION trickery to make it work. +# * Changed get-graphics to only accept a stem. +# * Fixed build-once logic for scripted .tex to work better +# * Made get-inputs sed script more maintainable. +# * Moved Makefile.ini import up higher. +# * Changed bare stems to not recursively invoke make +# * Updated diff output to be more silent everywhere +# * Added a MISSING comment to the .d file if stuff isn't found - forces +# removal of .1st.make file, which often forces it to try again. +# * Fixed broken graphics-target function +# * Added sleep to .d file generation when stuff is missing - if it +# builds too fast, make doesn't realize it needs to be reloaded, +# and thus never discovers some deeper dependencies (especially +# evident when graphics are included from scripted include +# files). +# Chris Monson (2010-03-17): +# * Bumped version to 2.2.0-beta6 +# * Fixed bareword builds to actually work (requires static patterns) +# * Fixed colorization to work with new paragraph stuff +# Chris Monson (2010-03-17): +# * Bumped version to 2.2.0-beta5 +# * Fixed graphic detection to be much more focused - splits log file +# into paragraphs before doing pattern matching. +# * Fixed make foo to work properly (recursively calls make foo.pdf) +# * Fixed gpi -> pdf generation to not waste time building .eps *after* +# the pdf already exists. +# * Changed log copies to include MAKE_RESTARTS as part of the name. +# * Fixed missing include file detection (also makes use of the paragraph +# stuff) to detect missing scripted include files. +# Chris Monson (2010-03-16): +# * Bumped version to 2.2.0-beta4 +# * issue 70: .pdf not moved out of the way properly on first +# compilation, resulting in early error detection failure. +# * issue 74: fixed broken error on missing .aux files: the +# implementation was masking real errors. +# Chris Monson (2010-03-15): +# * Bumped version to 2.2.0-beta3 +# * issue 71: Made the tput dependency optional +# * issue 73: Made .tex targets not pull in .d files (building them from +# scripts should not require a .d) +# * issue 74: Output a much saner error when a .aux file is not produced +# (e.g., when you are typing "make" without arguments in a +# directory with included .tex files that are not named with +# ._include_.) +# Chris Monson (2010-03-11): +# * Bumped version to 2.2.0-beta2 +# * Fixed clean-graphics to get rid of intermediate .eps files that may +# be hanging around +# * Added an automatic setting to use eps terminals in pdflatex mode for +# gnuplot if it doesn't understand pdf. +# * issue 66: Removed grayscale generation via magic suffix. Grayscale +# generation is now only available via GRAY=1 +# * issue 68: Added explicit handling of LC_ALL for locale-aware tools +# like "sort" +# Chris Monson (2010-03-10): +# * Bumped version to 2.2.0-beta1 +# * Fixed success message to handle output message in different places +# * Added name of produced file to success message +# Chris Monson (2010-03-10): +# * Bumped version to 2.2.0-alpha3 +# * Added meaningful error message for wrong hyperref options +# * Added meaningful error message for incorrect graphics extensions +# Chris Monson (2010-03-09): +# * Bumped version to 2.2.0-alpha2 +# * Updated graphics handling (gnuplot and fig generate pdf natively) +# * Changed xmgrace to output monochrome natively +# Chris Monson (2010-03-09): +# * Bumped version to 2.2.0-alpha1 - major change! +# * Support pdflatex natively and by default (issue 6 - a long time coming) +# * Add ability to have a single $HOME/.latex-makefile/Makefile.ini for +# all invocations +# * Reworked graphic inclusion detection so that extensions need not be +# specified for either build strategy (e.g., +# \includegraphics{test1.eps} -> \includegrahpics{test1}) +# * Changed log format to include filenames and line numbers +# Chris Monson (2010-02-04): +# * Bumped version to 2.1.43 +# * All of the following are for issue 63 (thanks to mojoh81): +# * Added documentation about fixing Makefile.ini default target +# * Added perl and python script targets +# * Fixed run logic to allow included .tex files to be scripted (the +# run-again logic now detects missing .tex files, and the MV +# command has been switched out for a command that only invokes +# MV if the files exist) +# * Changed scripted generation to only run once per make invocation +# * Added dependency on expr +# Chris Monson (2010-01-19): +# * Bumped version to 2.1.42 +# * issue 62: Added .brf extension to cleanable files (backrefs) +# Chris Monson (2010-01-07): +# * Bumped version to 2.1.41 +# * issue 60: bad makeindex runs now error out on subsequent tries +# Chris Monson (2009-12-01): +# * Bumped version to 2.1.40 +# * issue 36: build all indices (for e.g., splitidx usage) +# * issue 59: clean up all generated files (including indices) +# Chris Monson (2009-11-23): +# * Bumped version to 2.1.39 +# * issue 57: change ps2pdf invocations to just use gs directly +# Chris Monson (2009-11-19): +# * Bumped version to 2.1.38 +# * issue 57: Added some limited support for Cygwin (spaces in filenames) +# Chris Monson (2009-11-15): +# * Bumped version to 2.1.37 +# * Removed svninfo, since this is now managed by mercurial +# * Fixed typo in changelist +# * Issue 52: added jpg->eps conversion (thanks to brubakee) +# * Issue 54: fix missing Overfull colorization due to lack of a blank +# line preceding the first error. +# * Issue 51: remove head.tmp and body.tmp in make clean invocation +# * Issue 56: maintain multiple versions of log files (for debugging) +# Chris Monson (2009-11-14): +# * Bumped version to 2.1.36 +# * Issues 53 and 49: added .brf, .mtc, and .maf to the cleanables +# Chris Monson (2009-11-05): +# * Bumped version to 2.1.35 +# * Added nomenclature support (see issue 48) +# Chris Monson (2009-10-29): +# * Bumped version to 2.1.34 +# * Fixed _out_ creation bug introduced in 2.1.33 (it was always created) +# * Fixed erroneous help output for $HOME in BINARY_TARGET_DIR +# * Changed contact email address - bring on the spam! +# Chris Monson (2009-10-21): +# * Bumped version to 2.1.33 +# * Fixed issue 46, adding support for dot2tex (thanks to fdemesmay) +# * Made all_files.* settable in Makefile.ini (using ?= instead of :=) +# * Fixed issue 47, thanks to fdemesmay: add binary copy directory, copy +# dvi, pdf, and ps if it exists +# Chris Monson (2009-09-25): +# * Bumped version to 2.1.32 +# * Fixed so that a changed lol file will cause a rebuild +# * Added .lol files to the cleanable list +# Chris Monson (2009-09-08): +# * Bumped version to 2.1.31 +# * Closed issue 43: evince doesn't notice pdf change w/out touch +# Chris Monson (2009-08-28): +# * Bumped version to 2.1.30 +# * Closed issue 39: Capture multi-line log warnings/errors to output +# Chris Monson (2009-08-26): +# * Bumped version to 2.1.29 +# * Closed issue 42: add svg support using inkscape +# Chris Monson (2009-08-17): +# * Bumped version to 2.1.28 +# * Patch from paul.biggar for issue 38: package warnings are overlooked +# Chris Monson (2009-08-07): +# * Bumped version to 2.1.27 +# * Included patch for issue 37 - removes pdf/ps files before copying, +# allowing some broken viewers to see changes properly. +# Chris Monson (2009-05-15): +# * Bumped version to 2.1.26 +# * Included patch for issue 9 from favonia - detects .fig changes for +# pstex files during regular compilation, so long as the pstex +# has been built at least once with make all-pstex. +# Chris Monson (2009-03-27): +# * Bumped version to 2.1.25 +# * Cleaned up a bunch of variable setting stuff - more stuff is now +# settable from Makefile.ini +# * Cleaned up documentation for various features, especially settable +# variables. +# * issue 28: support for png -> eps conversion (it even looks good!) +# * issue 29: support for "neverclean" files in Makefile.ini +# * issue 30: make ps2pdf14 the default - fall back when not there +# Chris Monson (2009-03-09): +# * Bumped version to 2.1.24 +# * issue 27: xmgrace support (thanks to rolandschulzhd) +# Chris Monson (2008-10-23): +# * Bumped version to 2.1.23 +# * issue 23: fixed _check_programs to not use bash string subs +# Chris Monson (2008-09-02): +# * Bumped version to 2.1.22 +# * Appled patch from Holger <yllohy@googlemail.com> to add include +# sources and some documentation updates. +# * Updated backup_patterns to be a bit more aggressive (also thanks to +# Holger) +# Chris Monson (2008-08-30): +# * Bumped version to 2.1.21 +# * Added ability to specify onlysources.* variables to indicate the only +# files that should *not* be considered includes. Thanks to Holger +# <yllohy@googlemail.com> for this patch. +# * Added an automatic include of Makefile.ini if it exists. Allows +# settings to be made outside of this makefile. +# Chris Monson (2008-05-21): +# * Bumped version to 2.1.20 +# * Added manual pstex compilation support (run make all-pstex first) +# * Removed all automatic pstex support. It was totally breaking +# everything and is very hard to incorporate into the makefile +# concept because it requires LaTeX to *fail* before it can +# determine that it needs the files. +# Chris Monson (2008-04-17): +# * Bumped version to 2.1.19 +# * Changed the pstex build hack to be on by default +# Chris Monson (2008-04-09): +# * Bumped version to 2.1.18 +# * issue 16: fixed pstex build problems, seems nondeterministic. Added +# gratuitious hack for testing: set PSTEX_BUILD_ALL_HACK=1. +# Chris Monson (2008-04-09): +# * Bumped version to 2.1.17 +# * issue 20: fixed accumulation of <pid>*.make files - wildcard was +# refusing to work on files that are very recently created. +# Chris Monson (2008-04-02): +# * Bumped version to 2.1.16 +# * issue 19: Removed the use of "type" to fix broken "echo" settings +# Chris Monson (2008-03-27): +# * Bumped version to 2.1.15 +# * issue 18: Favors binary echo over builtin, as binary understands -n +# * issue 16: Fixed handling of missing pstex_t files in the log +# * issue 9: Added .SECONDARY target for .pstex files +# Chris Monson (2008-03-21): +# * Bumped version to 2.1.14 +# * Fixed broken aux file flattening, which caused included bibs to be +# missed. +# Chris Monson (2008-03-20): +# * Bumped version to 2.1.13 +# * Changed error output colorization to show errors for missing files +# that are not graphics files. +# Chris Monson (2008-03-20): +# * Bumped version to 2.1.12 +# * Fixed a regression introduced in r28 that makes bibtex fail when +# there is no index file present +# Chris Monson (2008-03-03): +# * Bumped version to 2.1.11 +# * Fixed issue 11 (handle index files, reported by abachn) +# * Cleaned up some comments and help text +# Chris Monson (2008-01-24): +# * Bumped version to 2.1.10 +# * Fixed to work when 'sh' is a POSIX shell like 'dash' +# Chris Monson (2007-12-12): +# * Bumped version to 2.1.9 +# * Fixed documentation and dependency graph for pstex files +# Chris Monson (2007-12-12): +# * Bumped version to 2.1.8 +# * Added basic pstex_t support for fig files (Issue 9 by favonia) +# I still suggest that psfrag be used instead. +# Chris Monson (2007-10-16): +# * Bumped version to 2.1.7 +# * Removed todo item: allow other comment directives for rst conversion +# * Added ability to use global rst style file _rststyle_._include_.tex +# * Added help text to that effect +# Chris Monson (2007-05-20): +# * Bumped version to 2.1.6 +# * Changed default paper size for rst files +# * Added todo item: fix paper size for rst files +# * Added todo item: allow other comment directives for rst conversion +# Chris Monson (2007-04-02): +# * Bumped version to 2.1.5 +# * Addressed Issue 7, incorrect .gpi.d generation in subdirectories +# Chris Monson (2007-03-28): +# * Bumped version to 2.1.4 +# * Fixed syntax error in dot output +# Chris Monson (2007-03-01): +# * Bumped version to 2.1.3 +# * Added reST to the included documentation +# * Fixed graphics and script generation to be settable in the +# environment. +# Chris Monson (2007-02-23): +# * Bumped version to 2.1.2 +# * Added the ability to generate .tex files from .rst files +# Chris Monson (2006-10-17): +# * Bumped version to 2.1.1 +# * Fixed includes from subdirectories (sed-to-sed slash escape problem) +# Chris Monson (2006-10-05): +# * Bumped version to 2.1.0 (pretty serious new feature added) +# * New feature: bib files can now be anywhere on the BIBINPUTS path +# * New programs: kpsewhich (with tetex) and xargs (BSD) +# Chris Monson (2006-09-28): +# * Bumped version to 2.0.9 +# * Added ability to parse more than one bibliography +# Chris Monson (2006-06-01): +# * Bumped version to 2.0.8 +# * Added .vrb to the list of cleaned files +# Chris Monson (2006-04-26): +# * Bumped version to 2.0.7 +# * Fixed so that clean-nographics does not remove .gpi.d files +# * Removed jpg -> eps hack (not working properly -- just pre-convert) +# * Fixed so that postscript grayscale can be done with BSD sed +# Chris Monson (2006-04-25): +# * Bumped version to 2.0.6 +# * Fixed so that changed toc, lot, lof, or out causes a rebuild +# Chris Monson (2006-04-17): +# * Bumped version to 2.0.5 +# * Added jpg -> eps conversion target +# Chris Monson (2006-04-12): +# * Bumped version to 2.0.4 +# * Fixed BSD sed invocation to not use \| as a branch delimiter +# * Added a comment section on what is and is not allowed in BSD sed +# * Made paper size handling more robust while I was at it +# * Fixed postscript RGB grayscale to use a weighted average +# * Fixed postscript HSB grayscale to convert to RGB first +# * Fixed a problem with rebuilding .bbl files +# Chris Monson (2006-04-11): +# * Bumped version to 2.0.3 +# * Fixed some BSD sed problems: can't use \n in substitutions +# Chris Monson (2006-04-10): +# * Bumped version to 2.0.2 +# * Once again removed ability to create .tex files from scripts +# * \includeonly works again +# Chris Monson (2006-04-09): +# * Bumped version to 2.0.1 +# * Fixed grayscale postscript handling to be more robust +# * Added ability to generate ._gray_. files from eps and eps.gz +# * Added ability to clean ._gray_.eps files created from .eps files +# Chris Monson (2006-04-07): +# * Bumped version to 2.0.0 +# * Removed clunky ability to create included .tex files from scripts +# * Added note in the help about included tex scripting not working +# * Fixed the .eps generation to delete %.gpihead.make when finished +# * Abandoned designs to use shell variables to create sed scripts +# * Abandoned __default__.tex.sh idea: it causes recursion with %: . +# * Removed web page to-do. All items are now complete. +# * Added better grayscale conversion for dot figures (direct ps fixup). +# * Include files can now be scripted (at the expense of \includeonly). +# * Updated dependency graph to contain better node names. +# Chris Monson (2006-04-06): +# * Bumped version to 2.0b3 +# * Top level includes now fail if there is no rule to build them +# * A helpful message is printed when they do fail +# * Grayscale has been changed to be ._gray_, other phonies use _ now, too +# * Grayscale handling has been completed +# * Changed _include_stems target to _includes target. +# * Fixed _includes target to be useful by itself. +# * Removed the ability to specify clean and build targets at once +# * Verified that epsfig works fine with current code +# * Fixed included scripts so that they are added to the dep files +# * Fixed so that graphics includes don't happen if they aren't for gpi +# * Fixed dot output to allow grayscale. +# Chris Monson (2006-04-05): +# * Bumped version to 2.0b2 +# * Removed automatic -gray output. It needs fixing in a bad way. +# * Revamped dependency creation completely. +# * Fixed conditional inclusion to actually work (test.nobuild.d, test.d). +# * Fixed clean target to remove log targets +# * Added the 'monochrome' word for gray gpi output +# * Added a _check_gpi_files target that checks for common problems +# * Changed the _version target into the version target (no _) +# * Added better handling of grayscale files. Use the .gray.pdf target. +# * Fixed testing for rebuilds +# Chris Monson (2006-04-04): +# * Bumped version to 2.0b1 +# * Changed colorization of output +# * Made .auxbbl and .auxtex .make files secondary targets +# * Shortened and simplified the final latex invocation loop +# * Added version-specific output ($$i vs. $$$$i) in latex loop +# * Added a build message for the first .dvi run (Building .dvi (0)) +# * Removed some build messages that most people don't care about. +# * Simplified procedure for user-set colors -- simple text specification +# * Fixed diff output to...not output. +# * Fixed rerun bug -- detect not only when preceded with LaTeX Warning +# * Sped up gpi plotting +# * Added error handling and colorized output for gpi failure +# * Documented color changing stuff. +# * Now sort the flattened aux file to avoid false recompilation needs +# * Added clean-nographics target +# * Don't remove self.dvi file if self.aux is missing in the log +# * Clarified some code. Did some very minor adjusting. +# Chris Monson (2006-04-03): +# * Bumped version to 2.0a7 +# * Added .dvi and .ps files as secondary files. +# * Fixed handling of multiple run detection when includeonly is in use. +# * Added code to flatten .aux files. +# * Added more files as .SECONDARY prerequisites to avoid recompilation. +# * Fixed the inputs generation to be much simpler and to use pipes. +# * Added the dependency graph directly into the makefile. +# * Changed flatten-aux to remove \@writefile \relax \newlabel, etc. +# * Undid pipe changes with sed usage (BSD sed doesn't know -f-). +# * Added a _check_programs target that tells you what your system has. +# * Fixed an error in colorization that made unnecessary errors appear +# * Added view targets. +# * Updated help text. +# * Augmented cookies so that .aux can trigger .bbl and .dvi rebuilds +# * Added more informative error handling for dvips and ps2pdf +# Chris Monson (2006-04-02): +# * Bumped version to 2.0a6 +# * Added indirection to .bbl dependencies to avoid rebuilding .bbl files +# * Streamlined the diff invocation to eliminate an existence test +# * Removed special shell quote escape variables +# * Moved includes to a more prominent location +# * Fixed .inputs.make to not contain .aux files +# * Fixed embedding to use a file instead of always grepping. +# * Added *.make.temp to the list of cleanable files +# * Fixed Ruby. It should now be supported properly. +# * Now differentiate between all, default, and buildable files. +# * Fixed to bail out on serious errors. +# * Revised the handling of includable files. Still working on it. +# Chris Monson (2006-03-31): +# * Bumped version to 2.0a5 +# * Fixed a bug with LaTeX error detection (there can be spaces) +# * Added .bbl support, simplifying everything and making it more correct +# * Refactored some tests that muddy the code +# * Did a little cleanup of some shell loops that can safely be make loops +# * Added support for graphviz .dot files +# * Made _all_programs output easier to read +# * Added the ruby support that has long been advertised +# * Font embedding was screwed up for PostScript -- now implicit +# * Changed the generation of -gray.gpi files to a single command +# * Changed any make-generated file that is not included from .d to .make +# Chris Monson (2006-03-30): +# * Bumped version to 2.0a4 +# * Fixed a bug with very long graphics file names +# * Added a todo entry for epsfig support +# * Fixed a bug paper size bug: sometimes more than one entry appears +# * Fixed DVI build echoing to display the number instead of process ID +# * DVI files are now removed on first invocation if ANY file is missing +# * Added a simple grayscale approach: if a file ends with -gray.gpi, it +# is created from the corresponding .gpi file with a special +# comment ##GRAY in its header, which causes coloring to be +# turned off. +# * Fixed a bug in the handling of .tex.sh files. For some reason I had +# neglected to define file stems for scripted output. +# * Removed a trailing ; from the %.graphics dependencies +# * Added dvips embedding (I think it works, anyway) +# Chris Monson (2006-03-29): +# * Bumped version to 2.0a3 +# * Fixed error in make 3.79 with MAKEFILE_LIST usage +# * Added the presumed filename to the _version output +# * Added a vim macro for converting sed scripts to make commands +# * Added gpi dependency support (plotting external files and loading gpi) +# * Allow .gpi files to be ignored if called .include.gpi or .nobuild.gpi +# * Fixed sed invocations where \+ was used. BSD sed uses \{1,\}. +# Chris Monson (2006-03-28): +# * Bumped version to 2.0a2 +# * Added SHELL_DEBUG and VERBOSE options +# * Changed the default shell back to /bin/sh (unset, in other words) +# * Moved .PHONY declarations closer to their targets +# * Moved help text into its own define block to obtain better formatting +# * Removed need for double-entry when adding a new program invocation +# * Moved .SECONDARY declaration closer to its relevant occurrence +# * Commented things more heavily +# * Added help text about setting terminal and output in gnuplot +# * Created more fine-grained clean targets +# * Added a %.graphics target that generates all of %'s graphics +# * Killed backward-compatible graphics generation (e.g., eps.gpi=gpi.eps) +# * For now, we're just GPL 2, not 3. Maybe it will change later +# * Made the version and svninfo into variables +# Chris Monson (2006-03-27): +# * Bumped version to 2.0a1 +# * Huge, sweeping changes -- automatic dependencies + +# IMPORTANT! +# +# When adding to the following list, do not introduce any blank lines. The +# list is extracted for documentation using sed and is terminated by a blank +# line. +# +# EXTERNAL PROGRAMS: +# = ESSENTIAL PROGRAMS = +# == Basic Shell Utilities == +CAT ?= cat +CP ?= cp -f +DIFF ?= diff +ECHO ?= echo +EGREP ?= egrep +ENV ?= env +EXPR ?= expr +MV ?= mv -f +SED ?= sed +SORT ?= sort +TOUCH ?= touch +UNIQ ?= uniq +WHICH ?= which +XARGS ?= xargs +SLEEP ?= sleep +# == LaTeX (tetex-provided) == +BIBTEX ?= bibtex +DVIPS ?= dvips +LATEX ?= latex +PDFLATEX ?= pdflatex +EPSTOPDF ?= epstopdf +MAKEINDEX ?= makeindex +KPSEWHICH ?= kpsewhich +GS ?= gs +# = OPTIONAL PROGRAMS = +# == Makefile Color Output == +TPUT ?= tput +# == TeX Generation == +PERL ?= perl +PYTHON ?= python +RST2LATEX ?= rst2latex.py +# == EPS Generation == +CONVERT ?= convert # ImageMagick +DOT ?= dot # GraphViz +DOT2TEX ?= dot2tex # dot2tex - add options (not -o) as needed +FIG2DEV ?= fig2dev # XFig +GNUPLOT ?= gnuplot # GNUplot +INKSCAPE ?= inkscape # Inkscape (svg support) +XMGRACE ?= xmgrace # XMgrace +PNGTOPNM ?= pngtopnm # From NetPBM - step 1 for png -> eps +PPMTOPGM ?= ppmtopgm # From NetPBM - (gray) step 2 for png -> eps +PNMTOPS ?= pnmtops # From NetPBM - step 3 for png -> eps +GUNZIP ?= gunzip # GZipped EPS +# == Beamer Enlarged Output == +PSNUP ?= psnup +# == Viewing Stuff == +VIEW_POSTSCRIPT ?= gv +VIEW_PDF ?= xpdf +VIEW_GRAPHICS ?= display + +# Command options for embedding fonts and postscript->pdf conversion +PS_EMBED_OPTIONS ?= -dPDFSETTINGS=/printer -dEmbedAllFonts=true -dSubsetFonts=true -dMaxSubsetPct=100 +PS_COMPATIBILITY ?= 1.4 + +# Defaults for GPI +DEFAULT_GPI_EPS_FONTSIZE ?= 22 +DEFAULT_GPI_PDF_FONTSIZE ?= 12 + +# Style file for ReST +RST_STYLE_FILE ?= $(wildcard _rststyle_._include_.tex) + +# This ensures that even when echo is a shell builtin, we still use the binary +# (the builtin doesn't always understand -n) +FIXED_ECHO := $(if $(findstring -n,$(shell $(ECHO) -n)),$(shell which echo),$(ECHO)) +ECHO := $(if $(FIXED_ECHO),$(FIXED_ECHO),$(ECHO)) + +define determine-gnuplot-output-extension +$(if $(shell $(WHICH) $(GNUPLOT)), + $(if $(findstring unknown or ambiguous, $(shell $(GNUPLOT) -e "set terminal pdf" 2>&1)), + eps, pdf), + none) +endef + +GNUPLOT_OUTPUT_EXTENSION ?= $(strip $(call determine-gnuplot-output-extension)) + +# Directory into which we place "binaries" if it exists. +# Note that this can be changed on the commandline or in Makefile.ini: +# +# Command line: +# make BINARY_TARGET_DIR=$HOME/pdfs myfile.pdf +# +# Also, you can specify a relative directory (relative to the Makefile): +# make BINARY_TARGET_DIR=pdfs myfile.pdf +# +# Or, you can use Makefile.ini: +# +# BINARY_TARGET_DIR := $(HOME)/bin_out +# +BINARY_TARGET_DIR ?= _out_ + +RESTARTS := $(if $(MAKE_RESTARTS),$(MAKE_RESTARTS),0) +# SH NOTES +# +# On some systems, /bin/sh, which is the default shell, is not linked to +# /bin/bash. While bash is supposed to be sh-compatible when invoked as sh, it +# just isn't. This section details some of the things you have to stay away +# from to remain sh-compatible. +# +# * File pattern expansion does not work for {} +# * [ "$x" = "$y" ] has to be [ x"$x" x"$y" ] +# * &> for stderr redirection doesn't work, use 2>&1 instead +# +# BSD SED NOTES +# +# BSD SED is not very nice compared to GNU sed, but it is the most +# commonly-invoked sed on Macs (being based on BSD), so we have to cater to +# it or require people to install GNU sed. It seems like the GNU +# requirement isn't too bad since this makefile is really a GNU makefile, +# but apparently GNU sed is much less common than GNU make in general, so +# I'm supporting it here. +# +# Sad experience has taught me the following about BSD sed: +# +# * \+ is not understood to mean \{1,\} +# * \| is meaningless (does not branch) +# * \n cannot be used as a substitution character +# * ? does not mean \{0,1\}, but is literal +# * a\ works, but only reliably for a single line if subsequent lines +# have forward slashes in them (as is the case in postscript) +# +# For more info (on the Mac) you can consult +# +# man -M /usr/share/man re_format +# +# And look for the word "Obsolete" near the bottom. + +# +# EXTERNAL PROGRAM DOCUMENTATION SCRIPT +# + +# $(call output-all-programs,[<output file>]) +define output-all-programs + [ -f '$(this_file)' ] && \ + $(SED) \ + -e '/^[[:space:]]*#[[:space:]]*EXTERNAL PROGRAMS:/,/^$$/!d' \ + -e '/EXTERNAL PROGRAMS/d' \ + -e '/^$$/d' \ + -e '/^[[:space:]]*#/i\ '\ + -e 's/^[[:space:]]*#[[:space:]][^=]*//' \ + $(this_file) $(if $1,> '$1',) || \ + $(ECHO) "Cannot determine the name of this makefile." +endef + +# If they misspell gray, it should still work. +GRAY ?= $(call get-default,$(GREY),) + +# +# Utility Functions and Definitions +# + +# While not exactly a make function, this vim macro is useful. It takes a +# verbatim sed script and converts each line to something suitable in a command +# context. Just paste the script's contents into the editor, yank this into a +# register (starting at '0') and run the macro once for each line of the +# original script: +# +# 0i -e :s/\$/$$/eg :s/'/'"'"'/eg ^Ela'A' \:noh j + +# don't call this directly - it is here to avoid calling wildcard more than +# once in remove-files. +remove-files-helper = $(if $1,$(RM) $1,$(sh_true)) + +# $(call remove-files,file1 file2) +remove-files = $(call remove-files-helper,$(wildcard $1)) + +# Removes all cleanable files in the given list +# $(call clean-files,file1 file2 file3 ...) +# Works exactly like remove-files, but filters out files in $(neverclean) +clean-files = \ + $(call remove-files-helper,$(call cleanable-files,$(wildcard $1))) + +# Outputs all generated files to STDOUT, along with some others that are +# created by these (e.g., .idx files end up producing .ilg and .ind files). +# Discovered by reading *.fls OUTPUT lines and producing corresponding .ind +# filenames as needed. +# +# $(call get-generated-names,<source recorder file (*.fls)>) +define get-generated-names +[ -f '$1' ] && \ +$(SED) \ + -e '/^OUTPUT /{' \ + -e ' s///' \ + -e ' p' \ + -e ' s/\.idx/\.ind/p' \ + -e ' s/\.ind/\.ilg/p' \ + -e '}' \ + -e 'd' \ + '$1' \ +| $(SORT) | $(UNIQ) +endef + +# This removes files without checking whether they are there or not. This +# sometimes has to be used when the file is created by a series of shell +# commands, but there ends up being a race condition: make doesn't know about +# the file generation as quickly as the system does, so $(wildcard ...) doesn't +# work right. Blech. +# $(call remove-temporary-files,filenames) +remove-temporary-files = $(if $1,$(RM) $1,:) + +# Create an identifier from a file name +# $(call cleanse-filename,filename) +cleanse-filename = $(subst .,_,$(subst /,__,$1)) + +# Escape dots +# $(call escape-dots,str) +escape-dots = $(subst .,\\.,$1) + +# Test that a file exists +# $(call test-exists,file) +test-exists = [ -e '$1' ] + +# $(call move-files,source,destination) +move-if-exists = $(call test-exists,$1) && $(MV) '$1' '$2' + +# Copy file1 to file2 only if file2 doesn't exist or they are different +# $(call copy-if-different,sfile,dfile) +copy-if-different = $(call test-different,$1,$2) && $(CP) '$1' '$2' +copy-if-exists = $(call test-exists,$1) && $(CP) '$1' '$2' +move-if-different = $(call test-different,$1,$2) && $(MV) '$1' '$2' +replace-if-different-and-remove = \ + $(call test-different,$1,$2) \ + && $(MV) '$1' '$2' \ + || $(call remove-files,'$1') + +# Note that $(DIFF) returns success when the files are the SAME.... +# $(call test-different,sfile,dfile) +test-different = ! $(DIFF) -q '$1' '$2' >/dev/null 2>&1 +test-exists-and-different = \ + $(call test-exists,$2) && $(call test-different,$1,$2) + +# Return value 1, or value 2 if value 1 is empty +# $(call get-default,<possibly empty arg>,<default value if empty>) +get-default = $(if $1,$1,$2) + +# Copy a file and log what's going on +# $(call copy-with-logging,<source>,<target>) +define copy-with-logging +if [ -d '$2/' ]; then \ + if $(CP) '$1' '$2/'; then \ + $(ECHO) "$(C_INFO)Copied '$1' to '$2/'$(C_RESET)"; \ + else \ + $(ECHO) "$(C_ERROR)Failed to copy '$1' to '$2/'$(C_RESET)"; \ + fi; \ +fi +endef + +# Gives a reassuring message about the failure to find include files +# $(call include-message,<list of include files>) +define include-message +$(strip \ +$(if $(filter-out $(wildcard $1),$1),\ + $(shell $(ECHO) \ + "$(C_INFO)NOTE: You may ignore warnings about the"\ + "following files:" >&2;\ + $(ECHO) >&2; \ + $(foreach s,$(filter-out $(wildcard $1),$1),$(ECHO) ' $s' >&2;)\ + $(ECHO) "$(C_RESET)" >&2) +)) +endef +# Characters that are hard to specify in certain places +space := $(empty) $(empty) +colon := \: +comma := , + +# Useful shell definitions +sh_true := : +sh_false := ! : + +# Clear out the standard interfering make suffixes +.SUFFIXES: + +# Turn off forceful rm (RM is usually mapped to rm -f) +ifdef SAFE_RM +RM := rm +endif + +# Turn command echoing back on with VERBOSE=1 +ifndef VERBOSE +QUIET := @ +endif + +# Turn on shell debugging with SHELL_DEBUG=1 +# (EVERYTHING is echoed, even $(shell ...) invocations) +ifdef SHELL_DEBUG +SHELL += -x +endif + +# Get the name of this makefile (always right in 3.80, often right in 3.79) +# This is only really used for documentation, so it isn't too serious. +ifdef MAKEFILE_LIST +this_file := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) +else +this_file := $(wildcard GNUmakefile makefile Makefile) +endif + +# Terminal color definitions + +REAL_TPUT := $(if $(NO_COLOR),,$(shell $(WHICH) $(TPUT))) + +# $(call get-term-code,codeinfo) +# e.g., +# $(call get-term-code,setaf 0) +get-term-code = $(if $(REAL_TPUT),$(shell $(REAL_TPUT) $1),) + +black := $(call get-term-code,setaf 0) +red := $(call get-term-code,setaf 1) +green := $(call get-term-code,setaf 2) +yellow := $(call get-term-code,setaf 3) +blue := $(call get-term-code,setaf 4) +magenta := $(call get-term-code,setaf 5) +cyan := $(call get-term-code,setaf 6) +white := $(call get-term-code,setaf 7) +bold := $(call get-term-code,bold) +uline := $(call get-term-code,smul) +reset := $(call get-term-code,sgr0) + +# +# User-settable definitions +# +LATEX_COLOR_WARNING ?= magenta +LATEX_COLOR_ERROR ?= red +LATEX_COLOR_INFO ?= green +LATEX_COLOR_UNDERFULL ?= magenta +LATEX_COLOR_OVERFULL ?= red bold +LATEX_COLOR_PAGES ?= bold +LATEX_COLOR_BUILD ?= cyan +LATEX_COLOR_GRAPHIC ?= yellow +LATEX_COLOR_DEP ?= green +LATEX_COLOR_SUCCESS ?= green bold +LATEX_COLOR_FAILURE ?= red bold + +# Gets the real color from a simple textual definition like those above +# $(call get-color,ALL_CAPS_COLOR_NAME) +# e.g., $(call get-color,WARNING) +get-color = $(subst $(space),,$(foreach c,$(LATEX_COLOR_$1),$($c))) + +# +# STANDARD COLORS +# +C_WARNING := $(call get-color,WARNING) +C_ERROR := $(call get-color,ERROR) +C_INFO := $(call get-color,INFO) +C_UNDERFULL := $(call get-color,UNDERFULL) +C_OVERFULL := $(call get-color,OVERFULL) +C_PAGES := $(call get-color,PAGES) +C_BUILD := $(call get-color,BUILD) +C_GRAPHIC := $(call get-color,GRAPHIC) +C_DEP := $(call get-color,DEP) +C_SUCCESS := $(call get-color,SUCCESS) +C_FAILURE := $(call get-color,FAILURE) +C_RESET := $(reset) + +# +# PRE-BUILD TESTS +# + +# Check that clean targets are not combined with other targets (weird things +# happen, and it's not easy to fix them) +hascleangoals := $(if $(sort $(filter clean clean-%,$(MAKECMDGOALS))),1) +hasbuildgoals := $(if $(sort $(filter-out clean clean-%,$(MAKECMDGOALS))),1) +ifneq "$(hasbuildgoals)" "" +ifneq "$(hascleangoals)" "" +$(error $(C_ERROR)Clean and build targets specified together$(C_RESET))) +endif +endif + +# +# VARIABLE DECLARATIONS +# + +# Names of sed scripts that morph gnuplot files -- only the first found is used +GNUPLOT_SED := global-gpi.sed gnuplot.sed +GNUPLOT_GLOBAL := global._include_.gpi gnuplot.global + +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +default_graphic_extension ?= eps +latex_build_program ?= $(LATEX) +build_target_extension ?= dvi +hyperref_driver_pattern ?= hdvips +hyperref_driver_error ?= Using dvips: specify ps2pdf in the hyperref options. +else +default_graphic_extension ?= pdf +latex_build_program ?= $(PDFLATEX) +build_target_extension ?= pdf +hyperref_driver_pattern ?= hpdf.* +hyperref_driver_error ?= Using pdflatex: specify pdftex in the hyperref options (or leave it blank). +endif + +# Files of interest +all_files.tex ?= $(wildcard *.tex) +all_files.tex.sh ?= $(wildcard *.tex.sh) +all_files.tex.pl ?= $(wildcard *.tex.pl) +all_files.tex.py ?= $(wildcard *.tex.py) +all_files.rst ?= $(wildcard *.rst) +all_files.fig ?= $(wildcard *.fig) +all_files.gpi ?= $(wildcard *.gpi) +all_files.dot ?= $(wildcard *.dot) +all_files.xvg ?= $(wildcard *.xvg) +all_files.svg ?= $(wildcard *.svg) +all_files.png ?= $(wildcard *.png) +all_files.jpg ?= $(wildcard *.jpg) +all_files.eps.gz ?= $(wildcard *.eps.gz) +all_files.eps ?= $(wildcard *.eps) + +# Utility function for obtaining all files not specified in $(neverclean) +# $(call cleanable-files,file1 file2 file3 ...) +# Returns the list of files that is not in $(wildcard $(neverclean)) +cleanable-files = $(filter-out $(wildcard $(neverclean)), $1) + +# Utility function for getting all .$1 files that are to be ignored +# * files listed in $(includes.$1) +# * files not listed in $(onlysources.$1) if it is defined +ignore_files = \ + $(includes.$1) \ + $(if $(onlysources.$1),$(filter-out $(onlysources.$1), $(all_files.$1))) + +# Patterns to never be allowed as source targets +ignore_patterns := %._include_ + +# Patterns allowed as source targets but not included in 'all' builds +nodefault_patterns := %._nobuild_ $(ignore_patterns) + +# Utility function for getting targets suitable building +# $(call filter-buildable,suffix) +filter-buildable = \ + $(filter-out $(call ignore_files,$1) \ + $(addsuffix .$1,$(ignore_patterns)),$(all_files.$1)) + +# Utility function for getting targets suitable for 'all' builds +# $(call filter-default,suffix) +filter-default = \ + $(filter-out $(call ignore_files,$1) \ + $(addsuffix .$1,$(nodefault_patterns)),$(all_files.$1)) + +# Top level sources that can be built even when they are not by default +files.tex := $(call filter-buildable,tex) +files.tex.sh := $(call filter-buildable,tex.sh) +files.tex.pl := $(call filter-buildable,tex.pl) +files.tex.py := $(call filter-buildable,tex.py) +files.rst := $(call filter-buildable,rst) +files.gpi := $(call filter-buildable,gpi) +files.dot := $(call filter-buildable,dot) +files.fig := $(call filter-buildable,fig) +files.xvg := $(call filter-buildable,xvg) +files.svg := $(call filter-buildable,svg) +files.png := $(call filter-buildable,png) +files.jpg := $(call filter-buildable,jpg) +files.eps.gz := $(call filter-buildable,eps.gz) + +# Make all pstex targets secondary. The pstex_t target requires the pstex +# target, and nothing else really depends on it, so it often gets deleted. +# This avoids that by allowing *all* fig files to be pstex targets, which is +# perfectly valid and causes no problems even if they're going to become eps +# files in the end. +.SECONDARY: $(patsubst %.fig,%.pstex,$(files.fig)) + +# Top level sources that are built by default targets +default_files.tex := $(call filter-default,tex) +default_files.tex.sh := $(call filter-default,tex.sh) +default_files.tex.pl := $(call filter-default,tex.pl) +default_files.tex.py := $(call filter-default,tex.py) +default_files.rst := $(call filter-default,rst) +default_files.gpi := $(call filter-default,gpi) +default_files.dot := $(call filter-default,dot) +default_files.fig := $(call filter-default,fig) +default_files.xvg := $(call filter-default,xvg) +default_files.svg := $(call filter-default,svg) +default_files.png := $(call filter-default,png) +default_files.jpg := $(call filter-default,jpg) +default_files.eps.gz := $(call filter-default,eps.gz) + +# Utility function for creating larger lists of files +# $(call concat-files,suffixes,[prefix]) +concat-files = $(foreach s,$1,$($(if $2,$2_,)files.$s)) + +# Useful file groupings +all_files_source := $(call concat-files,tex,all) +all_files_scripts := $(call concat-files,tex.sh tex.pl tex.py rst,all) + +.PHONY: $(all_files_scripts) + +default_files_source := $(call concat-files,tex,default) +default_files_scripts := $(call concat-files,tex.sh tex.pl tex.py rst,default) + +files_source := $(call concat-files,tex) +files_scripts := $(call concat-files,tex.sh tex.pl tex.py rst) + +# Utility function for obtaining stems +# $(call get-stems,suffix,[prefix]) +get-stems = $(sort $($(if $2,$2_,)files.$1:%.$1=%)) + +# List of all stems (including ._include_ and ._nobuild_ file stems) +all_stems.tex := $(call get-stems,tex,all) +all_stems.tex.sh := $(call get-stems,tex.sh,all) +all_stems.tex.pl := $(call get-stems,tex.pl,all) +all_stems.tex.py := $(call get-stems,tex.py,all) +all_stems.rst := $(call get-stems,rst,all) +all_stems.fig := $(call get-stems,fig,all) +all_stems.gpi := $(call get-stems,gpi,all) +all_stems.dot := $(call get-stems,dot,all) +all_stems.xvg := $(call get-stems,xvg,all) +all_stems.svg := $(call get-stems,svg,all) +all_stems.png := $(call get-stems,png,all) +all_stems.jpg := $(call get-stems,jpg,all) +all_stems.eps.gz := $(call get-stems,eps.gz,all) +all_stems.eps := $(call get-stems,eps,all) + +# List of all default stems (all default PDF targets): +default_stems.tex := $(call get-stems,tex,default) +default_stems.tex.sh := $(call get-stems,tex.sh,default) +default_stems.tex.pl := $(call get-stems,tex.pl,default) +default_stems.tex.py := $(call get-stems,tex.py,default) +default_stems.rst := $(call get-stems,rst,default) +default_stems.fig := $(call get-stems,fig,default) +default_stems.gpi := $(call get-stems,gpi,default) +default_stems.dot := $(call get-stems,dot,default) +default_stems.xvg := $(call get-stems,xvg,default) +default_stems.svg := $(call get-stems,svg,default) +default_stems.png := $(call get-stems,png,default) +default_stems.jpg := $(call get-stems,jpg,default) +default_stems.eps.gz := $(call get-stems,eps.gz,default) + +# List of all stems (all possible bare PDF targets created here): +stems.tex := $(call get-stems,tex) +stems.tex.sh := $(call get-stems,tex.sh) +stems.tex.pl := $(call get-stems,tex.pl) +stems.tex.py := $(call get-stems,tex.py) +stems.rst := $(call get-stems,rst) +stems.fig := $(call get-stems,fig) +stems.gpi := $(call get-stems,gpi) +stems.dot := $(call get-stems,dot) +stems.xvg := $(call get-stems,xvg) +stems.svg := $(call get-stems,svg) +stems.png := $(call get-stems,png) +stems.jpg := $(call get-stems,jpg) +stems.eps.gz := $(call get-stems,eps.gz) + +# Utility function for creating larger lists of stems +# $(call concat-stems,suffixes,[prefix]) +concat-stems = $(sort $(foreach s,$1,$($(if $2,$2_,)stems.$s))) + +# The most likely to be source but not finished product go first +graphic_source_extensions := fig \ + gpi \ + xvg \ + svg \ + dot \ + eps.gz + +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +graphic_source_extensions += png jpg +graphic_target_extensions := eps ps +else +graphic_source_extensions += eps +graphic_target_extensions := pdf png jpg mps tif +endif + +all_stems_source := $(call concat-stems,tex,all) +all_stems_script := $(call concat-stems,tex.sh tex.pl tex.py rst,all) +all_stems_graphic := $(call concat-stems,$(graphic_source_extensions),all) +all_stems_ss := $(sort $(all_stems_source) $(all_stems_script)) +all_stems_sg := $(sort $(all_stems_script)) +all_stems_ssg := $(sort $(all_stems_ss)) + +default_stems_source := $(call concat-stems,tex,default) +default_stems_script := $(call concat-stems,tex.sh tex.pl tex.py rst,default) +default_stems_ss := $(sort $(default_stems_source) $(default_stems_script)) +default_stems_sg := $(sort $(default_stems_script)) +default_stems_ssg := $(sort $(default_stems_ss)) + +stems_source := $(call concat-stems,tex) +stems_script := $(call concat-stems,tex.sh tex.pl tex.py rst) +stems_graphic := $(call concat-stems,$(graphic_source_extensions)) +stems_gg := $(sort $(stems_graphic)) +stems_ss := $(sort $(stems_source) $(stems_script)) +stems_sg := $(sort $(stems_script)) +stems_ssg := $(sort $(stems_ss)) + +# Calculate names that can generate the need for an include file. We can't +# really do this with patterns because it's too easy to screw up, so we create +# an exhaustive list. +allowed_source_suffixes := \ + pdf \ + ps \ + dvi \ + ind \ + nls \ + bbl \ + aux \ + aux.make \ + d \ + auxbbl.make \ + _graphics \ + _show +allowed_source_patterns := $(addprefix %.,$(allowed_source_suffixes)) + +allowed_graphic_suffixes := \ + pdf \ + eps \ + gpihead.make \ + gpi.d +allowed_graphic_patterns := $(addprefix %.,$(allowed_graphic_suffixes)) + +# All targets allowed to build documents +allowed_source_targets := \ + $(foreach suff,$(allowed_source_suffixes),\ + $(addsuffix .$(suff),$(stems_ssg))) + +# All targets allowed to build graphics +allowed_graphic_targets := \ + $(foreach suff,$(allowed_graphic_suffixes),\ + $(addsuffix .$(suff),$(stems_gg))) + +# All targets that build multiple documents (like 'all') +allowed_batch_source_targets := \ + all \ + all-pdf \ + all-ps \ + all-dvi \ + all-bbl \ + all-ind \ + all-gls \ + all-nls \ + show + +# All targets that build multiple graphics (independent of document) +allowed_batch_graphic_targets := \ + all-graphics \ + all-pstex \ + all-dot2tex \ + show-graphics + +# Now we figure out which stuff is available as a make target for THIS RUN. +real_goals := $(call get-default,$(filter-out _includes,$(MAKECMDGOALS)),\ + all) + +specified_source_targets := $(strip \ + $(filter $(allowed_source_targets) $(stems_ssg),$(real_goals)) \ + ) + +specified_batch_source_targets := $(strip \ + $(filter $(allowed_batch_source_targets),$(real_goals)) \ + ) + +specified_graphic_targets := $(strip \ + $(filter $(allowed_graphic_targets),$(real_goals)) \ + ) + +specified_batch_graphic_targets := $(strip \ + $(filter $(allowed_batch_graphic_targets),$(real_goals)) \ + ) + +specified_gpi_targets := $(patsubst %.gpi,%.$(default_graphic_extension),\ + $(filter $(patsubst %.$(default_graphic_extension),%.gpi,$(specified_graphic_targets)),\ + $(all_files.gpi)) \ + ) + +# Determine which .d files need including from the information gained above. +# This is done by first checking whether a batch target exists. If it does, +# then all *default* stems are used to create possible includes (nobuild need +# not apply for batch status). If no batch targets exist, then the individual +# targets are considered and appropriate includes are taken from them. +source_stems_to_include := \ + $(sort\ + $(if $(specified_batch_source_targets),\ + $(default_stems_ss),\ + $(foreach t,$(specified_source_targets),\ + $(foreach p,$(allowed_source_patterns),\ + $(patsubst $p,%,$(filter $p $(stems_ssg),$t)) \ + )) \ + )) + +# Determine which .gpi.d files are needed using the above information. We +# first check whether a batch target is specified, then check individual +# graphics that may have been specified. +graphic_stems_to_include := \ + $(sort\ + $(if $(specified_batch_graphic_targets),\ + $(default_stems.gpi),\ + $(foreach t,$(specified_gpi_targets),\ + $(foreach p,$(allowed_graphic_patterns),\ + $(patsubst $p,%,$(filter $p,$t)) \ + )) \ + )) + +# All dependencies for the 'all' targets +all_pdf_targets := $(addsuffix .pdf,$(stems_ssg)) +all_ps_targets := $(addsuffix .ps,$(stems_ssg)) +all_dvi_targets := $(addsuffix .dvi,$(stems_ssg)) +all_tex_targets := $(addsuffix .tex,$(stems_sg)) +all_d_targets := $(addsuffix .d,$(stems_ssg)) +all_graphics_targets := $(addsuffix .$(default_graphic_extension),$(stems_gg)) +intermediate_graphics_targets := $(if $(filter pdf,$(default_graphic_extension)),$(addsuffix .eps,$(stems_gg)),) +all_pstex_targets := $(addsuffix .pstex_t,$(stems.fig)) +all_dot2tex_targets := $(addsuffix .dot_t,$(stems.dot)) + +all_known_graphics := $(sort $(all_graphics_targets) $(wildcard *.$(default_graphic_extension))) + +default_pdf_targets := $(addsuffix .pdf,$(default_stems_ss)) +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +default_ps_targets := $(addsuffix .ps,$(default_stems_ss)) +default_dvi_targets := $(addsuffix .dvi,$(default_stems_ss)) +pre_pdf_extensions := dvi ps +endif + +# Extensions generated by LaTeX invocation that can be removed when complete +rm_ext := \ + log *.log aux $(pre_pdf_extensions) pdf blg bbl out nav snm toc lof lot lol pfg \ + fls vrb idx ind ilg glg glo gls lox nls nlo nlg brf mtc maf brf +backup_patterns := *~ *.bak *.backup body.tmp head.tmp + +graph_stem := _graph + +# All LaTeX-generated files that can be safely removed + +rm_tex := \ + $(foreach e,$(rm_ext),$(addsuffix .$e,$(all_stems_source))) \ + $(foreach e,$(rm_ext) tex,$(addsuffix .$e,$(all_stems_sg))) \ + $(addsuffix .log,$(all_ps_targets) $(all_pdf_targets)) \ + $(addsuffix .*.log,$(stems_graphic)) + +# These are the files that will affect .gpi transformation for all .gpi files. +# +# Use only the first one found. Backward compatible values are at the end. +# Note that we use foreach, even though wildcard also returns a list, to ensure +# that the order in the uppercase variables is preserved. Directory listings +# provide no such guarantee, so we avoid relying on them. +gpi_sed := $(strip \ + $(firstword $(foreach f,$(GNUPLOT_SED),$(wildcard $f)))) +gpi_global := $(strip \ + $(firstword $(foreach f,$(GNUPLOT_GLOBAL),$(wildcard $f)))) + +# +# Functions used in generating output +# + +# Outputs all source dependencies to stdout. The first argument is the file to +# be parsed, the second is a list of files that will show up as dependencies in +# the new .d file created here. +# +# NOTE: BSD sed does not understand \|, so we have to do something more +# clunky to extract suitable extensions. +# +# Also, we do a little bit of funny rewriting up front (TARGETS=) to make sure +# that we can properly backslash-escape spaces in file names (e.g, on Cygwin +# for tex distributions that have "Program Files" in their name). +# +# $(call get-inputs,<parsed file>,<target files>) +define get-inputs +$(SED) \ +-e '/^INPUT/!d' \ +-e 's!^INPUT \(\./\)\{0,1\}!!' \ +-e 's/[[:space:]]/\\ /g' \ +-e 's/\(.*\)\.aux$$/\1.tex/' \ +-e '/\.tex$$/b addtargets' \ +-e '/\.cls$$/b addtargets' \ +-e '/\.sty$$/b addtargets' \ +-e '/\.pstex_t$$/b addtargets' \ +-e '/\.dot_t$$/b addtargets' \ +-e 'd' \ +-e ':addtargets' \ +-e 's/^/$2: /' \ +$1 | $(SORT) | $(UNIQ) +endef + +# $(call get-missing-inputs,<log file>,<target files>) +define get-missing-inputs +$(SED) \ +-e '$$ b para' \ +-e '/^$$/b para' \ +-e 'H' \ +-e 'd' \ +-e ':para' \ +-e 'x' \ +-e '/^$$/d' \ +-e 's/^\n*//' \ +-e '/^! LaTeX Error: File /{' \ +-e ' s/^/::DOUBLE_PARAGRAPH::/' \ +-e ' h' \ +-e ' d' \ +-e '}' \ +-e 's/^::DOUBLE_PARAGRAPH:://' \ +-e '/Default extension: /!d' \ +-e 's/[[:space:]]\{1,\}/ /g' \ +-e 's/\n\{1,\}/ /g' \ +-e 's/^.*File `//' \ +-e 's/'"'"' not found\..*//' \ +-e '/\.tex/!s/$$/.tex/' \ +-e 's/[[:space:]]/\\ /g' \ +-e 'h' \ +-e 's/.*/# MISSING input "&" - (presence of comment affects build)/' \ +-e 'p' \ +-e 's/.*//' \ +-e 'x' \ +-e 's/^/$2: /' \ +$1 | $(SORT) | $(UNIQ) +endef + +# Get source file for specified graphics stem. +# +# $(call graphics-source,<stem>) +define graphics-source +$(strip $(firstword \ + $(wildcard \ + $(addprefix $1.,\ + $(graphic_source_extensions))) \ + $1 \ +)) +endef + +# Get the target file for the specified graphics file/stem +# +# $(call graphics-target,<stem>) +define graphics-target +$(strip $(if $(filter $(addprefix %.,$(graphic_target_extensions)),$1), $1, + $(firstword $(patsubst $(addprefix %.,$(graphic_source_extensions) $(graphic_target_extensions)), %, $1).$(default_graphic_extension) $1.$(default_graphic_extension)))) +endef + +# Outputs all of the graphical dependencies to stdout. The first argument is +# the stem of the source file being built, the second is a list of suffixes +# that will show up as dependencies in the generated .d file. +# +# Note that we try to escape spaces in filenames where possible. We have to do +# it with three backslashes so that as the name percolates through the makefile +# it eventually ends up with the proper escaping when the build rule is found. +# Ugly, but it appears to work. Note that graphicx doesn't allow filenames +# with spaces, so this could in many ways be moot unless you're using something +# like grffile. +# +# For pdflatex, we really need the missing file to be specified without an +# extension, otherwise compilation barfs on the first missing file. Truly +# annoying, but there you have it. +# +# It turns out that the graphics errors, although they have lines with empty +# space, are only made of two paragraphs. So, we just use some sed magic to +# get everything into paragraphs, detect when it's a paragraph that interests +# us, and double it up. Then we get the filename only if we're missing +# extensions (a sign that it's graphicx complaining). +# +# $(call get-graphics,<target file stem>) +#.log,$(addprefix $*.,d $(build_target_extension) _graphics) +define get-graphics +$(SED) \ +-e '$$ b para' \ +-e '/^$$/b para' \ +-e 'H' \ +-e 'd' \ +-e ':para' \ +-e 'x' \ +-e '/^$$/d' \ +-e 's/^\n*//' \ +-e '/^! LaTeX Error: File `/{' \ +-e ' s/^/::DOUBLE_PARAGRAPH::/' \ +-e ' h' \ +-e ' d' \ +-e '}' \ +-e 's/^::DOUBLE_PARAGRAPH:://' \ +-e '/could not locate the file with any of these extensions:/{' \ +-e ' s/\n\{1,\}/ /g' \ +-e ' s/[[:space:]]\{1,\}/ /g' \ +-e ' s/^.*File `//' \ +-e ' s/'"'"' not found\..*//' \ +-e ' h' \ +-e ' s/.*/# MISSING stem "&" - (presence of comment affects build)/' \ +-e ' p' \ +-e ' g' \ +-e ' b addtargets' \ +-e '}' \ +-e '/.*File: \(.*\) Graphic file (type [^)]*).*/{' \ +-e ' s//\1/' \ +-e ' b addtargets' \ +-e '}' \ +-e 'd' \ +-e ':addtargets' \ +-e 's/[[:space:]]/\\\\\\&/g' \ +-e 'h' \ +-e 's/.*/-include &.gpi.d/' \ +-e 'p' \ +-e 'g' \ +-e 's/.*/$(addprefix $1,.d): $$$$(call graphics-source,&)/' \ +-e 'p' \ +-e 's/.*//' \ +-e 'x' \ +-e 's/.*/$(addprefix $1.,$(build_target_extension) _graphics): $$$$(call graphics-target,&)/' \ +-e 'p' \ +-e 'd' \ +$*.log +endef + +# Checks for build failure due to pstex inclusion, and gives instructions. +# +# $(call die-on-pstexs,<parsed file>) +define die-on-pstexs +if $(EGREP) -q '^! LaTeX Error: File .*\.pstex.* not found' $1; then \ + $(ECHO) "$(C_ERROR)Missing pstex_t file(s)$(C_RESET)"; \ + $(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \ + $(ECHO) "$(C_ERROR) make all-pstex$(C_RESET)"; \ + $(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \ + exit 1; \ +fi +endef + +# Checks for build failure due to dot2tex, and gives instructions. +# +# $(call die-on-dot2tex,<parsed file>) +define die-on-dot2tex +if $(EGREP) -q ' LaTeX Error: File .*\.dot_t.* not found' $1; then \ + $(ECHO) "$(C_ERROR)Missing dot_t file(s)$(C_RESET)"; \ + $(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \ + $(ECHO) "$(C_ERROR) make all-dot2tex$(C_RESET)"; \ + $(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \ + exit 1; \ +fi +endef + +# Checks for the existence of a .aux file, and dies with an error message if it +# isn't there. Note that we pass the file stem in, not the full filename, +# e.g., to check for foo.aux, we call it thus: $(call die-on-no-aux,foo) +# +# $(call die-on-no-aux,<aux stem>) +define die-on-no-aux +if [ ! -e '$1.aux' ]; then \ + $(call colorize-latex-errors,$1.log); \ + exit 1; \ +fi +endef + +# Outputs all index files to stdout. Arg 1 is the source file stem, arg 2 is +# the list of targets for the discovered dependency. +# +# $(call get-log-index,<log file stem>,<target files>) +define get-log-index +$(SED) \ +-e 's/^No file \(.*\.ind\)\.$$/TARGETS=\1/' \ +-e 's/^No file \(.*\.[gn]ls\)\.$$/TARGETS=\1/' \ +-e 's/[[:space:]]/\\&/g' \ +-e '/^TARGETS=/{' \ +-e ' h' \ +-e ' s/^TARGETS=/$2: /p' \ +-e ' g' \ +-e ' s/^TARGETS=\(.*\)/\1: $1.tex/p' \ +-e '}' \ +-e 'd' \ +'$1.log' | $(SORT) | $(UNIQ) +endef + + +# Outputs all bibliography files to stdout. Arg 1 is the source stem, arg 2 is +# a list of targets for each dependency found. +# +# The script kills all lines that do not contain bibdata. Remaining lines have +# the \bibdata macro and delimiters removed to create a dependency list. A +# trailing comma is added, then all adjacent commas are collapsed into a single +# comma. Then commas are replaced with the string .bib[space], and the +# trailing space is killed off. Finally, all filename spaces are escaped. +# This produces a list of space-delimited .bib filenames, which is what the +# make dep file expects to see. +# +# Note that we give kpsewhich a bogus argument so that a failure of sed to +# produce output will not cause an error. +# +# $(call get-bibs,<aux file>,<targets>) +define get-bibs +$(SED) \ +-e '/^\\bibdata/!d' \ +-e 's/\\bibdata{\([^}]*\)}/\1,/' \ +-e 's/,\{2,\}/,/g' \ +-e 's/[[:space:]]/\\&/g' \ +-e 's/,/.bib /g' \ +-e 's/ \{1,\}$$//' \ +$1 | $(XARGS) $(KPSEWHICH) '#######' | \ +$(SED) \ +-e 's/^/$2: /' | \ +\$(SORT) | $(UNIQ) +endef + +# Makes a an aux file that only has stuff relevant to the target in it +# $(call make-auxtarget-file,<flattened-aux>,<new-aux>) +define make-auxtarget-file +$(SED) \ +-e '/^\\newlabel/!d' \ +$1 > $2 +endef + +# Makes an aux file that only has stuff relevant to the bbl in it +# $(call make-auxbbl-file,<flattened-aux>,<new-aux>) +define make-auxbbl-file +$(SED) \ +-e '/^\\newlabel/d' \ +$1 > $2 +endef + +# Makes a .gpi.d file from a .gpi file +# $(call make-gpi-d,<.gpi>,<.gpi.d>) +define make-gpi-d +$(ECHO) '# vim: ft=make' > $2; \ +$(ECHO) 'ifndef INCLUDED_$(call cleanse-filename,$2)' >> $2; \ +$(ECHO) 'INCLUDED_$(call cleanse-filename,$2) := 1' >> $2; \ +$(call get-gpi-deps,$1,$(addprefix $(2:%.gpi.d=%).,$(GNUPLOT_OUTPUT_EXTENSION) gpi.d)) >> $2; \ +$(ECHO) 'endif' >> $2; +endef + +# Parse .gpi files for data and loaded dependencies, output to stdout +# +# The sed script here tries to be clever about obtaining valid +# filenames from the gpi file. It assumes that the plot command starts its own +# line, which is not too difficult a constraint to satisfy. +# +# This command script also generates 'include' directives for every 'load' +# command in the .gpi file. The load command must appear on a line by itself +# and the file it loads must have the suffix .gpi. If you don't want it to be +# compiled when running make graphics, then give it a suffix of ._include_.gpi. +# +# $(call get-gpi-deps,<gpi file>,<targets>) +define get-gpi-deps +$(SED) \ +-e '/^[[:space:]]*s\{0,1\}plot/,/[^\\]$$/{' \ +-e ' H' \ +-e ' /[^\\]$$/{' \ +-e ' s/.*//' \ +-e ' x' \ +-e ' s/\\\{0,1\}\n//g' \ +-e ' s/^[[:space:]]*s\{0,1\}plot[[:space:]]*\(\[[^]]*\][[:space:]]*\)*/,/' \ +-e ' s/[[:space:]]*\(['\''"][^'\''"]*['\''"]\)\{0,1\}[^,]*/\1/g' \ +-e ' s/,['\''"]-\{0,1\}['\''"]//g' \ +-e ' s/[,'\''"]\{1,\}/ /g' \ +-e ' s!.*!$2: &!' \ +-e ' p' \ +-e ' }' \ +-e ' d' \ +-e '}' \ +-e 's/^[[:space:]]*load[[:space:]]*['\''"]\([^'\''"]*\.gpi\)['\''"].*$$/-include \1.d/p' \ +-e 'd' \ +$1 +endef + +# Colorizes real, honest-to-goodness LaTeX errors that can't be overcome with +# recompilation. +# +# Note that we only ignore file not found errors for things that we know how to +# build, like graphics files. +# +# $(call colorize-latex-errors,<log file>) +define colorize-latex-errors +$(SED) \ +-e '$$ b para' \ +-e '/^$$/b para' \ +-e 'H' \ +-e 'd' \ +-e ':para' \ +-e 'x' \ +-e '/^$$/d' \ +-e 's/^\n*//' \ +-e '/^! LaTeX Error: File /{' \ +-e ' s/^/::DOUBLE_PARAGRAPH::/' \ +-e ' h' \ +-e ' d' \ +-e '}' \ +-e 's/^::DOUBLE_PARAGRAPH:://' \ +-e '/could not locate the file with any of these extensions:/d' \ +-e '/Missing .begin.document/{' \ +-e ' h' \ +-e ' s/.*/Are you trying to build an include file?/' \ +-e ' x' \ +-e ' G' \ +-e '}' \ +-e '/ LaTeX Error: Cannot determine size/d' \ +-e 's/.* LaTeX Error .*/$(C_ERROR)&$(C_RESET)/p' \ +-e 's/Error: pdflatex (file .*/$(C_ERROR)& - try specifying it without an extension$(C_RESET)/p' \ +-e '/.*\*hyperref using.*driver \(.*\)\*.*/{' \ +-e ' s//\1/' \ +-e ' /^$(hyperref_driver_pattern)$$/!{' \ +-e ' s/.*//' \ +-e ' p' \ +-e ' s/.*/$(C_ERROR)--- Using incorrect driver for hyperref! ---$(C_RESET)/' \ +-e ' p' \ +-e ' s/.*/$(C_ERROR)$(hyperref_driver_error)$(C_RESET)/' \ +-e ' p' \ +-e ' }' \ +-e ' d' \ +-e '}' \ +-e '/ LaTeX Error: Unknown graphics extension/{' \ +-e ' s/^/ /' \ +-e ' h' \ +-e ' s/.*/--- Graphics extension error:/' \ +-e ' G' \ +-e ' h' \ +-e ' s/.*/--- If you specified the extension explicitly in your .tex file, try removing it./' \ +-e ' H' \ +-e ' g' \ +-e ' s/.*/$(C_ERROR)&$(C_RESET)/' \ +-e ' p' \ +-e ' s/.*//' \ +-e ' h' \ +-e ' b' \ +-e '}' \ +-e 's/.*\(\n\{0,\}! .*\)/$(C_ERROR)\1$(C_RESET)/p' \ +-e 'd' \ +$1 +endef + +# Colorize Makeindex errors +define colorize-makeindex-errors +$(SED) \ +-e '/^!! /{' \ +-e ' N' \ +-e ' s/^.*$$/$(C_ERROR)&$(C_RESET)/' \ +-e ' p' \ +-e '}' \ +-e 'd' \ +$1 +endef + +# Colorize epstopdf errors +# +# $(call colorize-epstopdf-errors,<log file>) +define colorize-epstopdf-errors +$(SED) \ +-e '/^Error:/,/^Execution stack:/{' \ +-e ' /^Execution stack:/d' \ +-e ' s/.*/$(C_ERROR)&$(C_RESET)/' \ +-e ' p' \ +-e '}' \ +-e 'd' \ +$1 +endef + +# Colorize GNUplot errors +# +# $(call colorize-gnuplot-errors,<log file>) +define colorize-gnuplot-errors +$(SED) \ +-e '/, line [0-9]*:/!{' \ +-e ' H' \ +-e ' x' \ +-e ' s/.*\n\(.*\n.*\)$$/\1/' \ +-e ' x' \ +-e '}' \ +-e '/, line [0-9]*:/{' \ +-e ' H' \ +-e ' /unknown.*terminal type/{' \ +-e ' s/.*/--- Try changing the GNUPLOT_OUTPUT_EXTENSION variable to 'eps'./' \ +-e ' H' \ +-e ' }' \ +-e ' /gpihead/{' \ +-e ' s/.*/--- This could be a Makefile bug - contact the maintainer./' \ +-e ' H' \ +-e ' }' \ +-e ' g' \ +-e ' s/.*/$(C_ERROR)&$(C_RESET)/' \ +-e ' p' \ +-e '}' \ +-e '/^gnuplot>/,/^$$/{' \ +-e ' s/^gnuplot.*/$(C_ERROR)&/' \ +-e ' s/^$$/$(C_RESET)/' \ +-e ' p' \ +-e '}' \ +-e 'd' \ +$1 +endef + +# Colorize GraphViz errors +# +# $(call colorize-dot-errors,<log file>) +define colorize-dot-errors +$(SED) \ +-e '/^Error:/,/context:/s/.*/$(C_ERROR)&$(C_RESET)/p' \ +-e 's/^Warning:.*/$(C_WARNING)&$(C_RESET)/p' \ +-e 'd' \ +'$1' +endef + +# Get all important .aux files from the top-level .aux file and merges them all +# into a single file, which it outputs to stdout. +# +# $(call flatten-aux,<toplevel aux>,<output file>) +define flatten-aux +$(SED) \ +-e '/\\@input{\(.*\)}/{' \ +-e 's//\1/' \ +-e 's![.:]!\\&!g' \ +-e 'h' \ +-e 's!.*!\\:\\\\@input{&}:{!' \ +-e 'p' \ +-e 'x' \ +-e 's/\\././g' \ +-e 's/.*/r &/p' \ +-e 's/.*/d/p' \ +-e 's/.*/}/p' \ +-e 'd' \ +-e '}' \ +-e 'd' \ +'$1' > "$1.$$$$.sed.make"; \ +$(SED) -f "$1.$$$$.sed.make" '$1' > "$1.$$$$.make"; \ +$(SED) \ +-e '/^\\relax/d' \ +-e '/^\\bibcite/d' \ +-e 's/^\(\\newlabel{[^}]\{1,\}}\).*/\1/' \ +"$1.$$$$.make" | $(SORT) > '$2'; \ +$(call remove-temporary-files,$1.$$$$.make $1.$$$$.sed.make) +endef + +# Generate pdf from postscript +# +# Note that we don't just call ps2pdf, since there are so many versions of that +# script on various systems. Instead, we call the postscript interpreter +# directly. +# +# $(call ps2pdf,infile,outfile,[embed fonts]) +define ps2pdf + $(GS) \ + -dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \ + $(if $3,$(PS_EMBED_OPTIONS)) \ + -q -dNOPAUSE -dBATCH \ + -sDEVICE=pdfwrite -sstdout=%stderr \ + '-sOutputFile=$2' \ + -dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \ + $(if $3,$(PS_EMBED_OPTIONS)) \ + -c .setpdfwrite \ + -f '$1' +endef + +# Colorize LaTeX output. +# This uses a neat trick from the Sed & Awk Book from O'Reilly: +# 1) If a line has a single ending paren, delete it to make a blank line (so +# that we catch the first error, which is not always preceded by a blank +# line). +# 2) Ensure that the last line of the file gets appended to the hold buffer, +# and blank it out to trigger end-of-paragraph logic below. +# 3) When encountering a blank line (LaTeX output helpfully breaks output on +# newlines) +# a) swap the hold buffer (containing the paragraph) into the pattern buffer (putting a blank line into the hold buffer), +# b) remove the newline at the beginning (don't ask), +# c) apply any colorizing substitutions necessary to ensure happiness. +# d) get the newline out of the hold buffer and append it +# e) profit! (print) +# 4) Anything not colorized is deleted, unless in verbose mode. +color_tex := \ + $(SED) \ + -e '$${' \ + -e ' /^$$/!{' \ + -e ' H' \ + -e ' s/.*//' \ + -e ' }' \ + -e '}' \ + -e '/^$$/!{' \ + -e ' H' \ + -e ' d' \ + -e '}' \ + -e '/^$$/{' \ + -e ' x' \ + -e ' s/^\n//' \ + -e ' /Output written on /{' \ + -e ' s/.*Output written on \([^(]*\) (\([^)]\{1,\}\)).*/Success! Wrote \2 to \1/' \ + -e ' s/[[:digit:]]\{1,\}/$(C_PAGES)&$(C_RESET)/g' \ + -e ' s/Success!/$(C_SUCCESS)&$(C_RESET)/g' \ + -e ' s/to \(.*\)$$/to $(C_SUCCESS)\1$(C_RESET)/' \ + -e ' b end' \ + -e ' }' \ + -e ' / *LaTeX Error:.*/{' \ + -e ' s/.*\( *LaTeX Error:.*\)/$(C_ERROR)\1$(C_RESET)/' \ + -e ' b end' \ + -e ' }' \ + -e ' /.*Warning:.*/{' \ + -e ' s//$(C_WARNING)&$(C_RESET)/' \ + -e ' b end' \ + -e ' }' \ + -e ' /Underfull.*/{' \ + -e ' s/.*\(Underfull.*\)/$(C_UNDERFULL)\1$(C_RESET)/' \ + -e ' b end' \ + -e ' }' \ + -e ' /Overfull.*/{' \ + -e ' s/.*\(Overfull.*\)/$(C_OVERFULL)\1$(C_RESET)/' \ + -e ' b end' \ + -e ' }' \ + $(if $(VERBOSE),,-e ' d') \ + -e ' :end' \ + -e ' G' \ + -e '}' \ + +# Colorize BibTeX output. +color_bib := \ + $(SED) \ + -e 's/^Warning--.*/$(C_WARNING)&$(C_RESET)/' -e 't' \ + -e '/---/,/^.[^:]/{' \ + -e ' H' \ + -e ' /^.[^:]/{' \ + -e ' x' \ + -e ' s/\n\(.*\)/$(C_ERROR)\1$(C_RESET)/' \ + -e ' p' \ + -e ' s/.*//' \ + -e ' h' \ + -e ' d' \ + -e ' }' \ + -e ' d' \ + -e '}' \ + -e '/(.*error.*)/s//$(C_ERROR)&$(C_RESET)/' \ + $(if $(VERBOSE),,-e 'd') + + +# Make beamer output big enough to print on a full page. Landscape doesn't +# seem to work correctly. +enlarge_beamer = $(PSNUP) -l -1 -W128mm -H96mm -pletter + +# $(call test-run-again,<source stem>) +test-run-again = $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.)$$' $1.log + +# This tests whether the build target commands should be run at all, from +# viewing the log file. +# $(call test-log-for-need-to-run,<source stem>) +define test-log-for-need-to-run +$(SED) \ +-e '/^No file $(call escape-dots,$1)\.aux\./d' \ +$1.log \ +| $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.|No file .+\.tex\.|LaTeX Warning: File.*)$$' +endef + +# LaTeX invocations +# +# $(call latex,<tex file>,[<extra LaTeX args>]) +run-latex = $(latex_build_program) --interaction=batchmode $(if $2,$2,) $1 > /dev/null + +# $(call latex-color-log,<LaTeX stem>) +latex-color-log = $(color_tex) $1.log + +# $(call run-makeindex,<input>,<output>,<log>,<extra flags>) +define run-makeindex +success=1; \ +if ! $(MAKEINDEX) -q $1 -t $3 -o $2 $4 > /dev/null || $(EGREP) -q '^!!' $3; then \ + $(call colorize-makeindex-errors,$3); \ + $(RM) -f '$2'; \ + success=0; \ +fi; \ +[ "$$success" = "1" ] && $(sh_true) || $(sh_false); +endef + +# This runs the given script to generate output, and it uses MAKE_RESTARTS to +# ensure that it never runs it more than once for a particular root make +# invocation. +# +# $(call run-script,<interpreter>,<input>,<output>) +define run-script +[ ! -e '$2.cookie' ] && $(ECHO) "restarts=$(RESTARTS)" > $2.cookie && $(ECHO) "level=$(MAKELEVEL)" >> $2.cookie; \ +restarts=`$(SED) -n -e 's/^restarts=//p' $2.cookie`; \ +level=`$(SED) -n -e 's/^level=//p' $2.cookie`; \ +if $(EXPR) $(MAKELEVEL) '<=' $$level '&' $(RESTARTS) '<=' $$restarts >/dev/null; then \ + $(call echo-build,$2,$3,$(RESTARTS)-$(MAKELEVEL)); \ + $1 '$2' '$3'; \ + $(ECHO) "restarts=$(RESTARTS)" > '$2.cookie'; \ + $(ECHO) "level=$(MAKELEVEL)" >> '$2.cookie'; \ +fi +endef + +# BibTeX invocations +# +# $(call run-bibtex,<tex stem>) +run-bibtex = $(BIBTEX) $1 | $(color_bib) + + +# $(call convert-eps-to-pdf,<eps file>,<pdf file>,[gray]) +# Note that we don't use the --filter flag because it has trouble with bounding boxes that way. +define convert-eps-to-pdf +$(if $3,$(CAT) '$1' | $(call kill-ps-color) > '$1.cookie',$(CP) '$1' '$1.cookie'); \ +$(EPSTOPDF) '$1.cookie' --outfile='$2' > $1.log; \ +$(call colorize-epstopdf-errors,$1.log); +endef + +# $(call convert-gpi,<gpi file>,<output file>,[gray]) +# +define convert-gpi +$(ECHO) 'set terminal $(if $(filter %.pdf,$2),pdf enhanced,postscript enhanced eps)' \ +$(if $(filter %.pdf,$2),fsize ,)$(call get-default,$(strip \ +$(firstword \ + $(shell \ + $(SED) \ + -e 's/^\#\#FONTSIZE=\([[:digit:]]\{1,\}\)/\1/p' \ + -e 'd' \ + $1 $(strip $(gpi_global)) \ + ) \ +) \ +),$(if $(filter %.pdf,$2),$(DEFAULT_GPI_PDF_FONTSIZE),$(DEFAULT_GPI_EPS_FONTSIZE))) \ +$(strip $(if $3,monochrome,$(if \ +$(shell $(EGREP) '^\#\#[[:space:]]*GRAY[[:space:]]*$$' $< $(gpi_global)),\ +,color))) > $1head.make; \ +$(ECHO) 'set output "$2"' >> $1head.make; \ +$(if $(gpi_global),$(CAT) $(gpi_global) >> $1head.make;,) \ +fnames='$1head.make $1';\ +$(if $(gpi_sed),\ + $(SED) -f '$(gpi_sed)' $$fnames > $1.temp.make; \ + fnames=$1.temp.make;,\ +) \ +success=1; \ +if ! $(GNUPLOT) $$fnames 2>$1.log; then \ + $(call colorize-gnuplot-errors,$1.log); \ + success=0; \ +fi; \ +$(if $(gpi_sed),$(call remove-temporary-files,$1.temp.make);,) \ +$(call remove-temporary-files,$1head.make); \ +[ "$$success" = "1" ] && $(sh_true) || $(sh_false); +endef + +# Creation of .eps files from .png files +# +# The intermediate step of PNM (using NetPBM) produces much nicer output than +# ImageMagick's "convert" binary. I couldn't get the right combination of +# flags to make it look nice, anyway. +# +# To handle gray scale conversion, we pipe things through ppmtopgm in the +# middle. +# +# $(call convert-png,<png file>,<eps file>) +define convert-png +$(PNGTOPNM) "$1" \ + $(if $3,| $(PPMTOPGM),) \ + | $(PNMTOPS) -noturn \ + > "$2" +endef + +# Creation of .eps files from .jpg files +# +# Thanks to brubakee for this solution. +# +# Uses Postscript level 2 to avoid file size bloat +# $(call convert-jpg,<jpg file>,<eps file>) +define convert-jpg +$(CONVERT) $(if $3,-type Grayscale,) '$1' eps2:'$2' +endef + +# Creation of .eps files from .fig files +# $(call convert-fig,<fig file>,<output file>,[gray]) +convert-fig = $(FIG2DEV) -L $(if $(filter %.pdf,$2),pdf,eps) $(if $3,-N,) $1 $2 + +# Creation of .pstex files from .fig files +# $(call convert-fig-pstex,<fig file>,<pstex file>) +convert-fig-pstex = $(FIG2DEV) -L pstex $1 $2 > /dev/null 2>&1 + +# Creation of .pstex_t files from .fig files +# $(call convert-fig-pstex-t,<fig file>,<pstex file>,<pstex_t file>) +convert-fig-pstex-t = $(FIG2DEV) -L pstex_t -p $3 $1 $2 > /dev/null 2>&1 + +# Creation of .dot_t files from .dot files +# #(call convert-dot-tex,<dot file>,<dot_t file>) +convert-dot-tex = $(DOT2TEX) '$1' > '$2' + +# Converts svg files into .eps files +# +# $(call convert-svg,<svg file>,<eps file>,[gray]) +convert-svg = $(INKSCAPE) --export-eps='$2' '$1' + +# Converts xvg files into .eps files +# +# $(call convert-xvg,<xvg file>,<eps file>,[gray]) +convert-xvg = $(XMGRACE) '$1' -printfile - -hardcopy -hdevice $(if $3,-mono,) EPS > '$2' + +# Converts .eps.gz files into .eps files +# +# $(call convert-epsgz,<eps.gz file>,<eps file>,[gray]) +convert-epsgz = $(GUNZIP) -c '$1' $(if $3,| $(call kill-ps-color)) > '$2' + +# Converts .eps files into .eps files (usually a no-op, but can make grayscale) +# +# $(call convert-eps,<in file>,<out file>,[gray]) +convert-eps = $(if $3,$(call kill-ps-color) $1 > $2) + +# The name of the file containing special postscript commands for grayscale +gray_eps_file := gray.eps.make + +# Changes sethsbcolor and setrgbcolor calls in postscript to always produce +# grayscale. In general, this is accomplished by writing new versions of those +# functions into the user dictionary space, which is looked up before the +# global or system dictionaries (userdict is one of the permanent dictionaries +# in postscript and is not read-only like systemdict). +# +# For setrgbcolor, the weighted average of the triple is computed and the +# triple is replaced with three copies of that average before the original +# procedure is called: .299R + .587G + .114B +# +# For sethsbcolor, the color is first converted to RGB, then to grayscale by +# the new setrgbcolor operator as described above. Why is this done? +# Because simply using the value component will tend to make pure colors +# white, a very undesirable thing. Pure blue should not translate to white, +# but to some level of gray. Conversion to RGB does the right thing. It's +# messy, but it works. +# +# From +# http://en.wikipedia.org/wiki/HSV_color_space#Transformation_from_HSV_to_RGB, +# HSB = HSV (Value = Brightness), and the formula used to convert to RGB is +# as follows: +# +# Hi = int(floor(6 * H)) mod 6 +# f = 6 * H - Hi +# p = V(1-S) +# q = V(1-fS) +# t = V(1-(1-f)S) +# if Hi = 0: R G B <-- V t p +# if Hi = 1: R G B <-- q V p +# if Hi = 2: R G B <-- p V t +# if Hi = 3: R G B <-- p q V +# if Hi = 4: R G B <-- t p V +# if Hi = 5: R G B <-- V p q +# +# The messy stack-based implementation is below +# $(call create-gray-eps-file,filename) +define create-gray-eps-file +$(ECHO) -n -e '\ +/OLDRGB /setrgbcolor load def\n\ +/setrgbcolor {\n\ + .114 mul exch\n\ + .587 mul add exch\n\ + .299 mul add\n\ + dup dup\n\ + OLDRGB\n\ +} bind def\n\ +/OLDHSB /sethsbcolor load def\n\ +/sethsbcolor {\n\ + 2 index % H V S H\n\ + 6 mul floor cvi 6 mod % Hi V S H\n\ + 3 index % H Hi V S H\n\ + 6 mul % 6H Hi V S H\n\ + 1 index % Hi 6H Hi V S H\n\ + sub % f Hi V S H\n\ + 2 index 1 % 1 V f Hi V S H\n\ + 4 index % S 1 V f Hi V S H\n\ + sub mul % p f Hi V S H\n\ + 3 index 1 % 1 V p f Hi V S H\n\ + 6 index % S 1 V p f Hi V S H\n\ + 4 index % f S 1 V p f Hi V S H\n\ + mul sub mul % q p f Hi V S H\n\ + 4 index 1 1 % 1 1 V q p f Hi V S H\n\ + 5 index % f 1 1 V q p f Hi V S H\n\ + sub % (1-f) 1 V q p f Hi V S H\n\ + 8 index % S (1-f) 1 V q p f Hi V S H\n\ + mul sub mul % t q p f Hi V S H\n\ + 4 -1 roll pop % t q p Hi V S H\n\ + 7 -2 roll pop pop % t q p Hi V\n\ + 5 -2 roll % Hi V t q p\n\ + dup 0 eq\n\ + {1 index 3 index 6 index}\n\ + {\n\ + dup 1 eq\n\ + {3 index 2 index 6 index}\n\ + {\n\ + dup 2 eq\n\ + {4 index 2 index 4 index}\n\ + {\n\ + dup 3 eq\n\ + {4 index 4 index 3 index}\n\ + {\n\ + dup 4 eq\n\ + {2 index 5 index 3 index}\n\ + {\n\ + dup 5 eq\n\ + {1 index 5 index 5 index}\n\ + {0 0 0}\n\ + ifelse\n\ + }\n\ + ifelse\n\ + }\n\ + ifelse\n\ + }\n\ + ifelse\n\ + }\n\ + ifelse\n\ + }\n\ + ifelse % B G R Hi V t q p\n\ + setrgbcolor\n\ + 5 {pop} repeat\n\ +} bind def\n'\ +> $1 +endef + +# This actually inserts the color-killing code into a postscript file +# $(call kill-ps-color) +define kill-ps-color +$(SED) -e '/%%EndComments/r $(gray_eps_file)' +endef + +# Converts graphviz .dot files into .eps files +# Grayscale is not directly supported by dot, so we pipe it through fig2dev in +# that case. +# $(call convert-dot,<dot file>,<eps file>,<log file>,[gray]) +define convert-dot +$(DOT) -Tps '$1' 2>'$3' $(if $4,| $(call kill-ps-color)) > $2; \ +$(call colorize-dot-errors,$3) +endef + +# Convert DVI to Postscript +# $(call make-ps,<dvi file>,<ps file>,<log file>,[<paper size>]) +make-ps = \ + $(DVIPS) -o '$2' $(if $(filter-out BEAMER,$4),-t$(firstword $4),) '$1' \ + $(if $(filter BEAMER,$4),| $(enlarge_beamer)) > $3 2>&1 + +# Convert Postscript to PDF +# $(call make-pdf,<ps file>,<pdf file>,<log file>,<embed file>) +make-pdf = \ + $(call ps2pdf,$1,$2,$(filter 1,$(shell $(CAT) '$4'))) > '$3' 2>&1 + +# Display information about what is being done +# $(call echo-build,<input file>,<output file>,[<run number>]) +echo-build = $(ECHO) "$(C_BUILD)= $1 --> $2$(if $3, ($3),) =$(C_RESET)" +echo-graphic = $(ECHO) "$(C_GRAPHIC)= $1 --> $2 =$(C_RESET)" +echo-dep = $(ECHO) "$(C_DEP)= $1 --> $2 =$(C_RESET)" + +# Display a list of something +# $(call echo-list,<values>) +echo-list = for x in $1; do $(ECHO) "$$x"; done + +# +# DEFAULT TARGET +# + +.PHONY: all +all: $(default_pdf_targets) ; + +.PHONY: all-pdf +all-pdf: $(default_pdf_targets) ; + +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +.PHONY: all-ps +all-ps: $(default_ps_targets) ; + +.PHONY: all-dvi +all-dvi: $(default_dvi_targets) ; +endif + +# +# VIEWING TARGET +# +.PHONY: show +show: all + $(QUIET)for x in $(default_pdf_targets); do \ + [ -e "$$x" ] && $(VIEW_PDF) $$x & \ + done + +# +# INCLUDES +# +source_includes := $(addsuffix .d,$(source_stems_to_include)) +graphic_includes := $(addsuffix .gpi.d,$(graphic_stems_to_include)) + +# Include only the dependencies used +ifneq "" "$(source_includes)" +include $(source_includes)$(call include-message,$(source_includes)) +endif +ifneq "" "$(graphic_includes)" +include $(graphic_includes)$(call include-message,$(graphic_includes)) +endif + +# +# MAIN TARGETS +# + +# Note that we don't just say %: %.pdf here - this can tend to mess up our +# includes, which detect what kind of file we are asking for. For example, +# asking to build foo.pdf is much different than asking to build foo when +# foo.gpi exists, because we look through all of the goals for *.pdf that +# matches *.gpi, then use that to determine which include files we need to +# build. +# +# Thus, we invoke make recursively with better arugments instead, restarting +# all of the appropriate machinery. +.PHONY: $(default_stems_ss) +$(default_stems_ss): %: %.pdf ; + +# This builds and displays the wanted file. +.PHONY: $(addsuffix ._show,$(stems_ssg)) +%._show: %.pdf + $(QUIET)$(VIEW_PDF) $< & + +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +.SECONDARY: $(all_pdf_targets) +%.pdf: %.ps %.embed.make + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call make-pdf,$<,$@.temp,$@.log,$*.embed.make); \ + if [ x"$$?" = x"0" ]; then \ + $(if $(VERBOSE),$(CAT) $@.log,:); \ + $(RM) -f '$@'; \ + $(MV) '$@.temp' '$@'; \ + $(TOUCH) '$@'; \ + $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \ + else \ + $(CAT) $@.log; \ + $(call remove-temporary-files,'$@.temp'); \ + $(sh_false); \ + fi + +.SECONDARY: $(all_ps_targets) +%.ps: %.dvi %.paper.make + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call make-ps,$<,$@.temp,$@.log,\ + $(firstword $(shell $(CAT) $*.paper.make))); \ + if [ x"$$?" = x"0" ]; then \ + $(if $(VERBOSE),$(CAT) $@.log,:); \ + $(RM) -f '$@'; \ + $(MV) '$@.temp' '$@'; \ + $(TOUCH) '$@'; \ + $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \ + else \ + $(CAT) $@.log; \ + $(call remove-temporary-files,'$@.temp'); \ + $(sh_false); \ + fi +endif + +# Build the final target (dvi or pdf) file. This is a very tricky rule because +# of the way that latex runs multiple times, needs graphics after the first run +# (or maybe already has them), and relies on bibliographies or indices that may +# not exist. +# +# Check the log for fatal errors. If they exist, colorize and bail. +# +# Create the .auxtarget.cookie file. (Needed for next time if not present) +# +# If any of the following are true, we must rebuild at least one time: +# +# * the .bbl was recently rebuilt +# +# check a cookie, then delete it +# +# * any of several output files was created or changed: +# +# check $*.run.cookie, then delete it +# +# * the .aux file changed in a way that necessitates attention +# +# Note that if the .auxtarget.make file doesn't exist, this means +# that we are doing a clean build, so it doesn't figure into the +# test for running again. +# +# compare against .auxtarget.make +# +# move if different, remove if not +# +# * the .log file has errors or warnings requiring at least one more run +# +# We use a loop over a single item to simplify the process of breaking +# out when we find one of the conditions to be true. +# +# If we do NOT need to run latex here, then we move the $@.1st.make file +# over to $@ because the target file has already been built by the first +# dependency run and is valid. +# +# If we do, we delete that cookie file and do the normal multiple-runs +# routine. +# +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +.SECONDARY: $(all_dvi_targets) +endif +%.$(build_target_extension): %.bbl %.aux %.$(build_target_extension).1st.make + $(QUIET)\ + fatal=`$(call colorize-latex-errors,$*.log)`; \ + if [ x"$$fatal" != x"" ]; then \ + $(ECHO) "$$fatal"; \ + exit 1; \ + fi; \ + $(call make-auxtarget-file,$*.aux.make,$*.auxtarget.cookie); \ + run=0; \ + for i in 1; do \ + if $(call test-exists,$*.bbl.cookie); then \ + run=1; \ + break; \ + fi; \ + if $(call test-exists,$*.run.cookie); then \ + run=1; \ + break; \ + fi; \ + if $(call \ + test-exists-and-different,$*.auxtarget.cookie,$*.auxtarget.make);\ + then \ + run=1; \ + break; \ + fi; \ + if $(call test-log-for-need-to-run,$*); then \ + run=1; \ + break; \ + fi; \ + done; \ + $(call remove-temporary-files,$*.bbl.cookie $*.run.cookie); \ + $(MV) $*.auxtarget.cookie $*.auxtarget.make; \ + if [ x"$$run" = x"1" ]; then \ + $(call remove-files,$@.1st.make); \ + for i in 2 3 4 5; do \ + $(if $(findstring 3.79,$(MAKE_VERSION)),\ + $(call echo-build,$*.tex,$@,$(RESTARTS)-$$$$i),\ + $(call echo-build,$*.tex,$@,$(RESTARTS)-$$i)\ + ); \ + $(call run-latex,$*); \ + $(CP) '$*.log' '$*.'$(RESTARTS)-$$i'.log'; \ + $(call test-run-again,$*) || break; \ + done; \ + else \ + $(MV) '$@.1st.make' '$@'; \ + fi; \ + $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \ + $(call latex-color-log,$*) + +# Build the .bbl file. When dependencies are included, this will (or will +# not!) depend on something.bib, which we detect, acting accordingly. The +# dependency creation also produces the %.auxbbl.make file. BibTeX is a bit +# finicky about what you call the actual files, but we can rest assured that if +# a .auxbbl.make file exists, then the .aux file does, as well. The +# .auxbbl.make file is a cookie indicating whether the .bbl needs to be +# rewritten. It only changes if the .aux file changes in ways relevant to .bbl +# creation. +# +# Note that we do NOT touch the .bbl file if there is no need to +# create/recreate it. We would like to leave existing files alone if they +# don't need to be changed, thus possibly avoiding a rebuild trigger. +%.bbl: %.auxbbl.make + $(QUIET)\ + $(if $(filter %.bib,$^),\ + $(call echo-build,$(filter %.bib,$?) $*.aux,$@); \ + $(call run-bibtex,$*); \ + $(TOUCH) $@.cookie; \ + ) \ + if $(EGREP) -q 'bibstyle.(apacann|chcagoa|[^}]*annot)' '$*.aux'; then \ + $(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-1); \ + $(call run-latex,$*); \ + $(CP) '$*.log' '$*.$(RESTARTS)-annotated.log'; \ + $(if $(filter %.bib,$^),\ + $(call echo-build,** annotated extra bibtex ** $(filter %.bib,$?) $*.aux,$@); \ + $(call run-bibtex,$*); \ + $(TOUCH) $@.cookie; \ + ) \ + $(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-2); \ + $(call run-latex,$*); \ + fi + +# Create the index file - note that we do *not* depend on %.tex here, since +# that unnecessarily restricts the kinds of indices that we can build to those +# with exactly the same stem as the source file. Things like splitidx create +# idx files with other names. +# +# Therefore, we add the .tex dependency in the sourcestem.d file in the call to +# get index file dependencies from the logs. +%.ind: %.idx + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call run-makeindex,$<,$@,$*.ilg) + +# Create the glossary file +%.gls: %.glo %.tex + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call run-makeindex,$<,$@,$*.glg,-s nomencl.ist) + +# Create the nomenclature file +%.nls: %.nlo %.tex + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call run-makeindex,$<,$@,$*.nlg,-s nomencl.ist) + +# SCRIPTED LaTeX TARGETS +# +# Keep the generated .tex files around for debugging if needed. +.SECONDARY: $(all_tex_targets) + +%.tex:: %.tex.sh + $(QUIET)$(call run-script,$(SHELL),$<,$@) + +%.tex:: %.tex.py + $(QUIET)$(call run-script,$(PYTHON),$<,$@) + +%.tex:: %.tex.pl + $(QUIET)$(call run-script,$(PERL),$<,$@) + +%.tex:: %.rst $(RST_STYLE_FILE) + $(QUIET)\ + $(call run-script,$(RST2LATEX)\ + --documentoptions=letterpaper\ + $(if $(RST_STYLE_FILE),--stylesheet=$(RST_STYLE_FILE),),$<,$@) + +# +# GRAPHICS TARGETS +# +.PHONY: all-graphics +all-graphics: $(all_graphics_targets); + +ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex" +.PHONY: all-pstex +all-pstex: $(all_pstex_targets); +endif + +.PHONY: all-dot2tex +all-dot2tex: $(all_dot2tex_targets); + +.PHONY: show-graphics +show-graphics: all-graphics + $(VIEW_GRAPHICS) $(all_known_graphics) + +$(gray_eps_file): + $(QUIET)$(call echo-build,$^,$@) + $(QUIET)$(call create-gray-eps-file,$@) + +ifeq "$(strip $(BUILD_STRATEGY))" "pdflatex" +%.pdf: %.eps $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-eps-to-pdf,$<,$@,$(GRAY)) + +ifeq "$(strip $(GNUPLOT_OUTPUT_EXTENSION))" "pdf" +%.pdf: %.gpi %.gpi.d $(gpi_sed) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-gpi,$<,$@,$(GRAY)) +endif + +%.pdf: %.fig + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-fig,$<,$@,$(GRAY)) + +endif + +%.eps: %.gpi %.gpi.d $(gpi_sed) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-gpi,$<,$@,$(GRAY)) + +%.eps: %.fig + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-fig,$<,$@,$(GRAY)) + +%.eps: %.dot $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-dot,$<,$@,$<.log,$(GRAY)) + +%.eps: %.xvg $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-xvg,$<,$@,$(GRAY)) + +%.eps: %.svg $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-svg,$<,$@,$(GRAY)) + +%.eps: %.jpg $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-jpg,$<,$@,$(GRAY)) + +%.eps: %.png $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-png,$<,$@,$(GRAY)) + +%.eps: %.eps.gz $(if $(GRAY),$(gray_eps_file)) + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-epsgz,$<,$@,$(GRAY)) + +%.pstex: %.fig + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-fig-pstex,$<,$@,$(GRAY)) + +%.pstex_t: %.fig %.pstex + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-fig-pstex-t,$<,$@,$*.pstex,$(GRAY)) + +%.dot_t: %.dot + $(QUIET)$(call echo-graphic,$^,$@) + $(QUIET)$(call convert-dot-tex,$<,$@) + +# +# DEPENDENCY-RELATED TARGETS. +# + +# Generate all of the information needed to get dependencies +# As a side effect, this creates a .dvi or .pdf file (depending on the build +# strategy). We need to be sure to remove it if there are errors. Errors can +# take several forms and all of them are found within the log file: +# * There was a LaTeX error +# * A needed file was not found +# * Cross references need adjustment +# +# Behavior: +# This rule is responsible for generating the following: +# %.aux +# %.d +# %.aux.make +# %.(pdf|dvi).1st.make (the .pdf or .dvi output file, moved) +# +# Steps: +# +# Run latex +# Move .pdf or .dvi somewhere else (make no judgements about success) +# Flatten the .aux file into another file +# Add source dependencies +# Add graphic dependencies +# Add bib dependencies +# +# Create cookies for various suffixes that may represent files that +# need to be read by LaTeX in order for it to function properly. +# +# Note that if some of the dependencies are discovered because they turn +# up missing in the log file, we really need the .d file to be reloaded. +# Adding a sleep command helps with this. Otherwise make is extremely +# nondeterministic, sometimes working, sometimes not. +# +# Usually we can force this by simply removing the generated pdf file and +# not creating a .1st.make file.. +# +%.$(build_target_extension).1st.make %.d %.aux %.aux.make %.fls: %.tex + $(QUIET)$(call echo-build,$<,$*.d $*.$(build_target_extension).1st.make,$(RESTARTS)-1) + $(QUIET)\ + $(call run-latex,$<,--recorder) || $(sh_true); \ + $(CP) '$*.log' '$*.$(RESTARTS)-1.log'; \ + $(call die-on-dot2tex,$*.log); \ + $(call die-on-no-aux,$*); \ + $(call flatten-aux,$*.aux,$*.aux.make); \ + $(ECHO) "# vim: ft=make" > $*.d; \ + $(ECHO) ".PHONY: $*._graphics" >> $*.d; \ + $(call get-inputs,$*.fls,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \ + $(call get-missing-inputs,$*.log,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \ + $(ECHO) ".SECONDEXPANSION:" >> $*.d; \ + $(call get-graphics,$*) >> $*.d; \ + $(call get-log-index,$*,$(addprefix $*.,d aux aux.make)) >> $*.d; \ + $(call get-bibs,$*.aux.make,$(addprefix $*.,bbl aux aux.make)) >> $*.d; \ + $(EGREP) -q "# MISSING" $*.d && $(SLEEP) 1 && $(RM) $*.pdf; \ + $(call move-if-exists,$*.$(build_target_extension),$*.$(build_target_extension).1st.make); \ + for s in toc out lot lof lol nav; do \ + if [ -e "$*.$$s" ]; then \ + if ! $(DIFF) -q $*.$$s $*.$$s.make >/dev/null 2>&1; then \ + $(TOUCH) $*.run.cookie; \ + fi; \ + $(CP) $*.$$s $*.$$s.make; \ + fi; \ + done + +# This is a cookie that is updated if the flattened aux file has changed in a +# way that affects the bibliography generation. +.SECONDARY: $(addsuffix .auxbbl.make,$(stems_ssg)) +%.auxbbl.make: %.aux.make + $(QUIET)\ + $(call make-auxbbl-file,$<,$@.temp); \ + $(call replace-if-different-and-remove,$@.temp,$@) + +# Build a dependency file for .gpi files. These often plot data files that +# also reside in the directory, so if a data file changes, it's nice to know +# about it. This also handles loaded .gpi files, whose filename should have +# _include_. in it. +%.gpi.d: %.gpi + $(QUIET)$(call echo-build,$<,$@) + $(QUIET)$(call make-gpi-d,$<,$@) + +# Store the paper size for this document -- note that if beamer is used we set +# it to the special BEAMER paper size. We only do this, however, if the +# special comment exists, in which case we enlarge the output with psnup. +# +# The paper size is extracted from a documentclass attribute. +%.paper.make: %.tex + $(QUIET)$(SED) \ + -e '/\\documentclass/,/}/{' \ + -e ' s/%.*//' \ + -e ' H' \ + -e ' /}/{' \ + -e ' s/.*//' \ + -e ' x' \ + -e ' /\\documentclass/!d' \ + -e ' s/[\n[:space:]]*//g' \ + -e ' s/\([,{[]\)\([[:alnum:]]\{1,\}\)paper\([],}]\)/\1%-\2-%\3/g' \ + -e ' s/\([,{[]\)\(landscape\)\([],}]\)/\1%-\2-%\3/g' \ + -e ' s/^[^%]*%-//' \ + -e ' s/-%[^%]*$$//' \ + -e ' s/-%[^%]%-/ /g' \ + -e ' p' \ + -e ' }' \ + -e ' d' \ + -e '}' \ + -e 'd' \ + $< > $@; \ + $(EGREP) -q '^[^%]*\\documentclass[^{]*{beamer}' $< && \ + (\ + $(EGREP) -q '^%%[[:space:]]*BEAMER[[:space:]]*LARGE$$' $< && \ + $(ECHO) "BEAMER" > $@ || \ + : > $@ \ + ) || $(sh_true) + +# Store embedding instructions for this document using a special comment +%.embed.make: %.tex + $(QUIET)$(EGREP) '^%%[[:space:]]*NO[[:space:]]*EMBED[[:space:]]*$$' $< \ + && $(ECHO) '' > $@ \ + || $(ECHO) '1' > $@; + +# +# HELPFUL PHONY TARGETS +# + +.PHONY: _all_programs +_all_programs: + $(QUIET)$(ECHO) "== All External Programs Used ==" + $(QUIET)$(call output-all-programs) + +.PHONY: _check_programs +_check_programs: + $(QUIET)$(ECHO) "== Checking Makefile Dependencies =="; $(ECHO) + $(QUIET) \ + $(ECHO) hi; \ + allprogs=`\ + ($(call output-all-programs)) | \ + $(SED) \ + -e 's/^[[:space:]]*//' \ + -e '/^#/d' \ + -e 's/[[:space:]]*#.*//' \ + -e '/^=/s/[[:space:]]/_/g' \ + -e '/^[[:space:]]*$$/d' \ + -e 's/^[^=].*=[[:space:]]*\([^[:space:]]\{1,\}\).*$$/\\1/' \ + `; \ + spaces=' '; \ + for p in $${allprogs}; do \ + case $$p in \ + =*) $(ECHO); $(ECHO) "$$p";; \ + *) \ + $(ECHO) -n "$$p:$$spaces" | $(SED) -e 's/^\(.\{0,20\}\).*$$/\1/'; \ + loc=`$(WHICH) $$p`; \ + if [ x"$$?" = x"0" ]; then \ + $(ECHO) "$(C_SUCCESS)Found:$(C_RESET) $$loc"; \ + else \ + $(ECHO) "$(C_FAILURE)Not Found$(C_RESET)"; \ + fi; \ + ;; \ + esac; \ + done + +.PHONY: _check_gpi_files +_check_gpi_files: + $(QUIET)$(ECHO) "== Checking all .gpi files for common errors =="; \ + $(ECHO); \ + for f in $(files.gpi); do \ + result=`$(EGREP) '^([^#]*set terminal |set output )' $$f`; \ + $(ECHO) -n "$$f: "; \ + if [ x"$$result" = x"" ]; then \ + $(ECHO) "$(C_SUCCESS)Okay$(C_RESET)"; \ + else \ + $(ECHO) "$(C_FAILURE)Warning: Problematic commands:$(C_RESET)";\ + $(ECHO) "$(C_ERROR)$$result$(C_RESET)"; \ + fi; \ + done; \ + $(ECHO) + +.PHONY: _all_stems +_all_stems: + $(QUIET)$(ECHO) "== All Stems ==" + $(QUIET)$(call echo-list,$(sort $(default_stems_ss))) + +.PHONY: _includes +_includes: + $(QUIET)$(ECHO) "== Include Stems ==" + $(QUIET)$(ECHO) "=== Sources ===" + $(QUIET)$(call echo-list,$(sort $(source_includes))) + $(QUIET)$(ECHO) "=== Graphics ===" + $(QUIET)$(call echo-list,$(sort $(graphic_includes))) + +.PHONY: _all_sources +_all_sources: + $(QUIET)$(ECHO) "== All Sources ==" + $(QUIET)$(call echo-list,$(sort $(all_files.tex))) + +.PHONY: _dependency_graph +_dependency_graph: + $(QUIET)$(ECHO) "/* LaTeX Dependency Graph */" + $(QUIET)$(call output-dependency-graph) + +.PHONY: _show_dependency_graph +_show_dependency_graph: + $(QUIET)$(call output-dependency-graph,$(graph_stem).dot) + $(QUIET)$(DOT) -Tps -o $(graph_stem).eps $(graph_stem).dot + $(QUIET)$(VIEW_POSTSCRIPT) $(graph_stem).eps + $(QUIET)$(call remove-temporary-files,$(graph_stem).*) + +.PHONY: _sources +_sources: + $(QUIET)$(ECHO) "== Sources ==" + $(QUIET)$(call echo-list,$(sort $(files.tex))) + +.PHONY: _scripts +_scripts: + $(QUIET)$(ECHO) "== Scripts ==" + $(QUIET)$(call echo-list,$(sort $(files_scripts))) + +.PHONY: _graphic_outputs +_graphic_outputs: + $(QUIET)$(ECHO) "== Graphic Outputs ==" + $(QUIET)$(call echo-list,$(sort $(all_graphics_targets))) + +.PHONY: _env +_env: +ifdef .VARIABLES + $(QUIET)$(ECHO) "== MAKE VARIABLES ==" + $(QUIET)$(call echo-list,$(foreach var,$(sort $(.VARIABLES)),'$(var)')) +endif + $(QUIET)$(ECHO) "== ENVIRONMENT ==" + $(QUIET)$(ENV) + +# +# CLEAN TARGETS +# +# clean-generated is somewhat unique - it relies on the .fls file being +# properly built so that it can determine which of the files was generated, and +# which was not. Expect it to silently fail if the .fls file is missing. +# +# This is used to, e.g., clean up index files that are generated by the LaTeX. +.PHONY: clean-generated +clean-generated: + $(QUIET)$(call clean-files,$(foreach e,$(addsuffix .fls,$(all_stems_source)),\ + $(shell $(call get-generated-names,$e)))) + +.PHONY: clean-deps +clean-deps: + $(QUIET)$(call clean-files,$(all_d_targets) *.make *.make.temp *.cookie) + +.PHONY: clean-tex +clean-tex: clean-deps + $(QUIET)$(call clean-files,$(rm_tex)) + +.PHONY: clean-graphics +# TODO: This *always* deletes pstex files, even if they were not generated by +# anything.... In other words, if you create a pstex and pstex_t pair by hand +# an drop them in here without the generating fig file, they will be deleted +# and you won't get them back. It's a hack put in here because I'm not sure we +# even want to keep pstex functionality, so my motivation is not terribly high +# for doing it right. +clean-graphics: + $(QUIET)$(call clean-files,$(all_graphics_targets) $(intermediate_graphics_targets) *.gpi.d *.pstex *.pstex_t *.dot_t) + +.PHONY: clean-backups +clean-backups: + $(QUIET)$(call clean-files,$(backup_patterns) *.temp) + +.PHONY: clean-auxiliary +clean-auxiliary: + $(QUIET)$(call clean-files,$(graph_stem).*) + +.PHONY: clean-nographics +clean-nographics: clean-tex clean-deps clean-backups clean-auxiliary ; + +.PHONY: clean +clean: clean-generated clean-tex clean-graphics clean-deps clean-backups clean-auxiliary + +# +# HELP TARGETS +# + +.PHONY: help +help: + $(help_text) + +.PHONY: version +version: + $(QUIET)\ + $(ECHO) "$(fileinfo) Version $(version)"; \ + $(ECHO) "by $(author)"; \ + +# +# HELP TEXT +# + +define help_text +# $(fileinfo) Version $(version) +# +# by $(author) +# +# Generates a number of possible output files from a LaTeX document and its +# various dependencies. Handles .bib files, \include and \input, and .eps +# graphics. All dependencies are handled automatically by running LaTeX over +# the source. +# +# USAGE: +# +# make [GRAY=1] [VERBOSE=1] [SHELL_DEBUG=1] <target(s)> +# +# STANDARD OPTIONS: +# GRAY: +# Setting this variable forces all recompiled graphics to be grayscale. +# It is useful when creating a document for printing. The default is +# to allow colors. Note that it only changes graphics that need to be +# rebuilt! It is usually a good idea to do a 'make clean' first. +# +# VERBOSE: +# This turns off all @ prefixes for commands invoked by make. Thus, +# you get to see all of the gory details of what is going on. +# +# SHELL_DEBUG: +# This enables the -x option for sh, meaning that everything it does is +# echoed to stderr. This is particularly useful for debugging +# what is going on in $$(shell ...) invocations. One of my favorite +# debugging tricks is to do this: +# +# make -d SHELL_DEBUG=1 VERBOSE=1 2>&1 | less +# +# STANDARD AUXILIARY FILES: +# +# Makefile.ini +# +# This file can contain variable declarations that override various +# aspects of the makefile. For example, one might specify +# +# neverclean := *.pdf *.ps +# onlysources.tex := main.tex +# LATEX_COLOR_WARNING := 'bold red uline' +# +# And this would override the neverclean setting to ensure that pdf +# and ps files always remain behind, set the makefile to treat all +# .tex files that are not "main.tex" as includes (and therefore not +# default targets). It also changes the LaTeX warning output to be +# red, bold, and underlined. +# +# There are numerous variables in this file that can be overridden in +# this way. Search for '?=' to find them all. +# +# Also, you can put arbitrary targets into it if, for example, you +# want your source built from something else, e.g.: +# +# generated.tex: generating_script.weird_lang depA depB +# ./generating_script.weird_lang > $$@ +# +# Note that if you are not careful, you can override the default +# target (what happens when you type "make" without arguments), so if +# you do use Makefile.ini, you probably want to start it with +# something like the following line: +# +# default: all +# +# Since the first target in any makefile is automatically the default, +# and the makefile already has a sensible "all" target, this will do +# what you want. +# +# The Makefile.ini is imported before *anything else* is done, so go +# wild with your ideas for changes to this makefile in there. It +# makes it easy to test them before submitting patches. +# +# STANDARD ENVIRONMENT VARIABLES: +# +# LATEX_COLOR_WARNING '$(LATEX_COLOR_WARNING)' +# LATEX_COLOR_ERROR '$(LATEX_COLOR_ERROR)' +# LATEX_COLOR_UNDERFULL '$(LATEX_COLOR_UNDERFULL)' +# LATEX_COLOR_OVERFULL '$(LATEX_COLOR_OVERFULL)' +# LATEX_COLOR_PAGES '$(LATEX_COLOR_PAGES)' +# LATEX_COLOR_BUILD '$(LATEX_COLOR_BUILD)' +# LATEX_COLOR_GRAPHIC '$(LATEX_COLOR_GRAPHIC)' +# LATEX_COLOR_DEP '$(LATEX_COLOR_DEP)' +# LATEX_COLOR_SUCCESS '$(LATEX_COLOR_SUCCESS)' +# LATEX_COLOR_FAILURE '$(LATEX_COLOR_FAILURE)' +# +# These may be redefined in your environment to be any of the following: +# +# black +# red +# green +# yellow +# blue +# magenta +# cyan +# white +# +# Bold or underline may be used, as well, either alone or in combination +# with colors: +# +# bold +# uline +# +# Order is not important. You may want, for example, to specify: +# +# export LATEX_COLOR_SUCCESS='bold blue uline' +# +# in your .bashrc file. I don't know why, but you may want to. +# +# STANDARD TARGETS: +# +# all: +# Make all possible documents in this directory. The documents are +# determined by scanning for .tex and .tex.sh (described in more detail +# later) and omitting any file that ends in ._include_.tex or +# ._nobuild_.tex. The output is a set of .pdf files. +# +# If you wish to omit files without naming them with the special +# underscore names, set the following near the top of the Makefile, +# or (this is recommended) within a Makefile.ini in the same directory: +# +# includes.tex := file1.tex file2.tex +# +# This will cause the files listed to be considered as include files. +# +# If you have only few source files, you can set +# +# onlysources.tex := main.tex +# +# This will cause only the source files listed to be considered in +# dependency detection. All other .tex files will be considered as +# include files. Note that these options work for *any* source type, +# so you could do something similar with includes.gpi, for example. +# Note that this works for *any valid source* target. All of the +# onlysources.* variables are commented out in the shipping version of +# this file, so it does the right thing when they simply don't exist. +# The comments are purely documentation. If you know, for example, that +# file.mycoolformat is supported by this Makefile, but don't see the +# "onlysources.mycoolformat" declared in the comments, that doesn't mean +# you can't use it. Go ahead and set "onlysources.mycoolformat" and it +# should do the right thing. +# +# show: +# Builds and displays all documents in this directory. It uses the +# environment-overridable value of VIEW_PDF (currently $(VIEW_PDF)) to +# do its work. +# +# all-graphics: +# Make all of the graphics in this directory. +# +# all-pstex (only for BUILD_STRATEGY=latex): +# Build all fig files into pstex and pstex_t files. Gray DOES NOT WORK. +# +# all-gray-pstex (only for BUILD_STRATEGY=latex): +# Build all fig files into grayscale pstex and pstex_t files. +# +# all-dot2tex: +# Build all dot files into tex files. +# +# show-graphics: +# Builds and displays all graphics in this directory. Uses the +# environment-overridable value of VIEW_GRAPHICS (currently +# $(VIEW_GRAPHICS)) to do its work. +# +# clean: +# Remove ALL generated files, leaving only source intact. +# This will *always* skip files mentioned in the "neverclean" variable, +# either in this file or specified in Makefile.ini: +# +# neverclean := *.pdf *.ps +# +# The neverclean variable works on all "clean" targets below, as well. +# +# clean-graphics: +# Remove all generated graphics files. +# +# clean-backups: +# Remove all backup files: $(backup_patterns) +# (XFig and other editors have a nasty habit of leaving them around) +# Also removes Makefile-generated .temp files +# +# clean-tex: +# Remove all files generated from LaTeX invocations except dependency +# information. Leaves graphics alone. +# +# clean-deps: +# Removes all auto-generated dependency information. +# +# clean-auxiliary: +# Removes extra files created by various targets (like the dependency +# graph output). +# +# clean-nographics: +# Cleans everything *except* the graphics files. +# +# help: +# This help text. +# +# version: +# Version information about this LaTeX makefile. +# +# DEBUG TARGETS: +# +# _all_programs: +# A list of the programs used by this makefile. +# +# _check_programs: +# Checks your system for the needed software and reports what it finds. +# +# _check_gpi_files: +# Checks the .gpi files in the current directory for common errors, such +# as specification of the terminal or output file inside of the gpi file +# itself. +# +# _dependency_graph: +# Outputs a .dot file to stdout that represents a graph of LaTeX +# dependencies. To see it, use the _show_dependency_graph target or +# direct the output to a file, run dot on it, and view the output, e.g.: +# +# make _dependency_graph > graph.dot +# dot -T ps -o graph.eps graph.dot +# gv graph.eps +# +# _show_dependency_graph: +# Makes viewing the graph simple: extracts, builds and displays the +# dependency graph given in the _dependency_graph target using the value +# of the environment-overridable VIEW_POSTSCRIPT variable (currently set +# to $(VIEW_POSTSCRIPT)). The postscript viewer is used because it +# makes it easier to zoom in on the graph, a critical ability for +# something so dense and mysterious. +# +# _all_sources: +# List all .tex files in this directory. +# +# _sources: +# Print out a list of all compilable sources in this directory. This is +# useful for determining what make thinks it will be using as the +# primary source for 'make all'. +# +# _scripts: +# Print out a list of scripts that make knows can be used to generate +# .tex files (described later). +# +# _all_stems: +# Print a list of stems. These represent bare targets that can be +# executed. Listing <stem> as a bare target will produce <stem>.pdf. +# +# _includes: +# A list of .d files that would be included in this run if _includes +# weren't specified. This target may be used alone or in conjunction +# with other targets. +# +# _graphic_outputs: +# A list of all generated .eps files +# +# _env: +# A list of environment variables and their values. If supported by +# your version of make, also a list of variables known to make. +# +# FILE TARGETS: +# +# %, %.pdf: +# Build a PDF file from the corresponding %.tex file. +# +# If BUILD_STRATEGY=pdflatex, then this builds the pdf directly. +# Otherwise, it uses this old-school but effective approach: +# +# latex -> dvips -> ps2pdf +# +# The BUILD_STRATEGY can be overridden in Makefile.ini in the same +# directory. The default is pdflatex. +# +# Reasons for using latex -> dvips include the "psfrag" package, and the +# generation of postscript instead of PDF. Arguments for using pdflatex +# include "new and shiny" and "better supported." I can't argue with +# either of those, and supporting them both didn't turn out to be that +# difficult, so there you have it. Choices. +# +# %._show: +# A phony target that builds the pdf file and then displays it using the +# environment-overridable value of VIEW_PDF ($(VIEW_PDF)). +# +# %._graphics: +# A phony target that generates all graphics on which %.pdf (or %.dvi) +# depends. +# +# %.ps (only for BUILD_STRATEGY=latex): +# Build a Postscript file from the corresponding %.tex file. +# This is done using dvips. Paper size is automatically +# extracted from the declaration +# +# \documentclass[<something>paper] +# +# or it is the system default. +# +# If using beamer (an excellent presentation class), the paper +# size is ignored. More on this later. +# +# %.dvi (only for BUILD_STRATEGY=latex): +# Build the DVI file from the corresponding %.tex file. +# +# %.ind: +# Build the index for this %.tex file. +# +# %.gls: +# Build the nomenclature glossary for this %.tex file. +# +# %.nls: +# Build the (newer) nomenclature file for this %.tex file. +# +# %.eps: +# Build an eps file from one of the following file types: +# +# .dot : graphviz +# .gpi : gnuplot +# .fig : xfig +# .xvg : xmgrace +# .svg : scalable vector graphics (goes through inkscape) +# .png : png (goes through NetPBM) +# .jpg : jpeg (goes through ImageMagick) +# .eps.gz : gzipped eps +# +# The behavior of this makefile with each type is described in +# its own section below. +# +# %.pstex{,_t} (only for BUILD_STRATEGY=latex): +# Build a .pstex_t file from a .fig file. +# +# FEATURES: +# +# Optional Binary Directory: +# If you create the _out_ directory in the same place as the makefile, +# it will automatically be used as a dumping ground for .pdf (or .dvi, +# .ps, and .pdf) output files. +# +# Alternatively, you can set the BINARY_TARGET_DIR variable, either as a +# make argument or in Makefile.ini, to point to your directory of +# choice. Note that no pathname wildcard expansion is done in the +# makefile, so make sure that the path is complete before going in +# there. E.g., if you want to specify something in your home directory, +# use $$HOME/ instead of ~/ so that the shell expands it before it gets +# to the makefile. +# +# External Program Dependencies: +# Every external program used by the makefile is represented by an +# ALLCAPS variable at the top of this file. This should allow you to +# make judgments about whether your system supports the use of this +# makefile. The list is available in the ALL_PROGRAMS variable and, +# provided that you are using GNU make 3.80 or later (or you haven't +# renamed this file to something weird like "mylatexmakefile" and like +# invoking it with make -f) can be viewed using +# +# make _all_programs +# +# Additionally, the availability of these programs can be checked +# automatically for you by running +# +# make _check_programs +# +# The programs are categorized according to how important they are and +# what function they perform to help you decide which ones you really +# need. +# +# Colorized Output: +# The output of commands is colorized to highlight things that are often +# important to developers. This includes {underfull,overfull} +# {h,v}boxes, general LaTeX Errors, each stage of document building, and +# the number of pages in the final document. The colors are obtained +# using 'tput', so colorization should work pretty well on any terminal. +# +# The colors can be customized very simply by setting any of the +# LATEX_COLOR_<CONTEXT> variables in your environment (see above). +# +# Predecessors to TeX Files: +# Given a target <target>, if no <target>.tex file exists but a +# corresponding script or predecessor file exists, then appropriate +# action will be taken to generate the tex file. +# +# Currently supported script or predecessor languages are: +# +# sh: %.tex.sh +# perl: %.tex.pl +# python: %.tex.py +# +# Calls the script using the appropriate interpreter, assuming that +# its output is a .tex file. +# +# The script is called thus: +# +# <interpreter> <script file name> <target tex file> +# +# and therefore sees exactly one parameter: the name of the .tex +# file that it is to create. +# +# Why does this feature exist? I ran into this while working on +# my paper dissertation. I wrote a huge bash script that used a +# lot of sed to bring together existing papers in LaTeX. It +# would have been nice had I had something like this to make my +# life easier, since as it stands I have to run the script and +# then build the document with make. This feature provides hooks +# for complicated stuff that you may want to do, but that I have +# not considered. It should work fine with included dependencies, +# too. +# +# Scripts are run every time make is invoked. Some trickery is +# employed to make sure that multiple restarts of make don't cause +# them to be run again. +# +# reST: %.rst +# +# Runs the reST to LaTeX converter to generate a .tex file +# If it finds a file names _rststyle_._include_.tex, uses it as +# the "stylesheet" option to rst2latex. +# +# Note that this does not track sub-dependencies in rst files. It +# assumes that the top-level rst file will change if you want a +# rebuild. +# +# Dependencies: +# +# In general, dependencies are extracted directly from LaTeX output on +# your document. This includes +# +# * Bibliography information +# * \include or \input files (honoring \includeonly, too) +# * Graphics files inserted by the graphicx package +# +# Where possible, all of these are built correctly and automatically. +# In the case of graphics files, these are generated from the following +# file types: +# +# GraphViz: .dot +# GNUPlot: .gpi +# XFig: .fig +# XMgrace: .xvg +# SVG: .svg +# PNG: .png +# JPEG: .jpg +# GZipped EPS: .eps.gz +# +# If the file exists as a .eps already, it is merely used (and will not +# be deleted by 'clean'!). +# +# LaTeX and BibTeX are invoked correctly and the "Rerun to get +# cross-references right" warning is heeded a reasonable number of +# times. In my experience this is enough for even the most troublesome +# documents, but it can be easily changed (if LaTeX has to be run after +# BibTeX more than three times, it is likely that something is moving +# back and forth between pages, and no amount of LaTeXing will fix +# that). +# +# \includeonly is honored by this system, so files that are not +# specified there will not trigger a rebuild when changed. +# +# Beamer: +# A special TeX source comment is recognized by this makefile (only when +# BUILD_STRATEGY=latex, since this invokes psnup): +# +# %%[[:space:]]*BEAMER[[:space:]]*LARGE +# +# The presence of this comment forces the output of dvips through psnup +# to enlarge beamer slides to take up an entire letter-sized page. This +# is particularly useful when printing transparencies or paper versions +# of the slides. For some reason landscape orientation doesn't appear +# to work, though. +# +# If you want to put multiple slides on a page, use this option and then +# print using mpage, a2ps, or psnup to consolidate slides. My personal +# favorite is a2ps, but your mileage may vary. +# +# When beamer is the document class, dvips does NOT receive a paper size +# command line attribute, since beamer does special things with sizes. +# +# GNUPlot Graphics: +# When creating a .gpi file, DO NOT INCLUDE the "set terminal" or "set +# output" commands! The makefile will include terminal information for +# you. Besides being unnecessary and potentially harmful, including the +# terminal definition in the .gpi file makes it harder for you, the one +# writing the document, to preview your graphics, e.g., with +# +# gnuplot -persist myfile.gpi +# +# so don't do specify a terminal or an output file in your .gpi files. +# +# When building a gpi file into an eps file, there are several features +# available to the document designer: +# +# Global Header: +# The makefile searches for the files in the variable GNUPLOT_GLOBAL +# in order: +# +# ($(GNUPLOT_GLOBAL)) +# +# Only the first found is used. All .gpi files in the directory are +# treated as though the contents of GNUPLOT_GLOBAL were directly +# included at the top of the file. +# +# NOTE: This includes special comments! (see below) +# +# Font Size: +# A special comment in a .gpi file (or a globally included file) of +# the form +# +# ## FONTSIZE=<number> +# +# will change the font size of the GPI output. If font size is +# specified in both the global file and the GPI file, the +# specification in the individual GPI file is used. +# +# Grayscale Output: +# GNUplot files also support a special comment to force them to be +# output in grayscale *no matter what*: +# +# ## GRAY +# +# This is not generally advisable, since you can always create a +# grayscale document using the forms mentioned above. But, if your +# plot simply must be grayscale even in a document that allows +# colors, this is how you do it. +# +# XFig Graphics: +# No special handling is done with XFig, except when a global +# grayscale method is used, e.g. +# +# make GRAY=1 document +# +# In these cases the .eps files is created using the -N switch to +# fig2dev to turn off color output. (Only works with eps, not pstex +# output) +# +# GraphVis Graphics: +# Color settings are simply ignored here. The 'dot' program is used +# to transform a .dot file into a .eps file. +# +# If you want, you can use the dot2tex program to convert dot files +# to tex graphics. The default is to just call dot2tex with no +# arguments, but you can change the DOT2TEX definition to include +# options as needed (in your Makefile.ini). +# +# Note that, as with pstex, the makefile cannot use latex's own +# output to discover all missing dot_t (output) files, since anytime +# TeX includes TeX, it has to bail when it can't find the include +# file. It can therefore only stop on the first missing file it +# discovers, and we can't get a large list of them out easily. +# +# So, the makefile errors out if it's missing an included dot_t +# file, then prompts the user to run this command manually: +# +# make all-dot2tex +# +# GZipped EPS Graphics: +# +# A .eps.gz file is sometimes a nice thing to have. EPS files can get +# very large, especially when created from bitmaps (don't do this if you +# don't have to). This makefile will unzip them (not in place) to +# create the appropriate EPS file. +# +endef + +# +# DEPENDENCY CHART: +# +#digraph "g" { +# rankdir=TB +# size="9,9" +# edge [fontsize=12 weight=10] +# node [shape=box fontsize=14 style=rounded] +# +# eps [ +# shape=Mrecord +# label="{{<gpi> GNUplot|<epsgz> GZip|<dot> Dot|<fig> XFig}|<eps> eps}" +# ] +# pstex [label="%.pstex"] +# pstex_t [label="%.pstex_t"] +# tex_outputs [shape=point] +# extra_tex_files [shape=point] +# gpi_data [label="<data>"] +# gpi_includes [label="_include_.gpi"] +# aux [label="%.aux"] +# fls [label="%.fls"] +# idx [label="%.idx"] +# glo [label="%.glo"] +# ind [label="%.ind"] +# log [label="%.log"] +# tex_sh [label="%.tex.sh"] +# rst [label="%.rst"] +# tex [ +# shape=record +# label="<tex> %.tex|<include> _include_.tex" +# ] +# include_aux [label="_include_.aux"] +# file_bib [label=".bib"] +# bbl [label="%.bbl"] +# dvi [label="%.dvi"] +# ps [label="%.ps"] +# pdf [label="%.pdf"] +# fig [label=".fig"] +# dot [label=".dot"] +# gpi [label=".gpi"] +# eps_gz [label=".eps.gz"] +# +# gpi_files [shape=point] +# +# rst -> tex:tex [label="reST"] +# tex_sh -> tex:tex [label="sh"] +# tex_pl -> tex:tex [label="perl"] +# tex_py -> tex:tex [label="python"] +# tex -> tex_outputs [label="latex"] +# tex_outputs -> dvi +# tex_outputs -> aux +# tex_outputs -> log +# tex_outputs -> fls +# tex_outputs -> idx +# tex_outputs -> include_aux +# aux -> bbl [label="bibtex"] +# file_bib -> bbl [label="bibtex"] +# idx -> ind [label="makeindex"] +# glo -> gls [label="makeindex"] +# nlo -> nls [label="makeindex"] +# gls -> extra_tex_files +# nls -> extra_tex_files +# ind -> extra_tex_files +# bbl -> extra_tex_files +# eps -> extra_tex_files +# extra_tex_files -> dvi [label="latex"] +# gpi_files -> eps:gpi [label="gnuplot"] +# gpi -> gpi_files +# gpi_data -> gpi_files +# gpi_includes -> gpi_files +# eps_gz -> eps:epsgz [label="gunzip"] +# fig -> eps:fig [label="fig2dev"] +# fig -> pstex [label="fig2dev"] +# fig -> pstex_t [label="fig2dev"] +# pstex -> pstex_t [label="fig2dev"] +# dot -> eps:dot [label="dot"] +# dvi -> ps [label="dvips"] +# include_aux -> bbl [label="bibtex"] +# ps -> pdf [label="ps2pdf"] +# +# edge [ color=blue label="" style=dotted weight=1 fontcolor=blue] +# fls -> tex:include [label="INPUT: *.tex"] +# fls -> file_bib [label="INPUT: *.aux"] +# aux -> file_bib [label="\\bibdata{...}"] +# include_aux -> file_bib [label="\\bibdata{...}"] +# log -> gpi [label="Graphic file"] +# log -> fig [label="Graphic file"] +# log -> eps_gz [label="Graphic file"] +# log -> dot [label="Graphic file"] +# log -> idx [label="No file *.ind"] +# log -> glo [label="No file *.gls"] +# log -> nlo [label="No file *.nls"] +# gpi -> gpi_data [label="plot '...'"] +# gpi -> gpi_includes [label="load '...'"] +# tex:tex -> ps [label="paper"] +# tex:tex -> pdf [label="embedding"] +#} + +# +# DEPENDENCY CHART SCRIPT +# +# $(call output_dependency_graph,[<output file>]) +define output-dependency-graph + if [ -f '$(this_file)' ]; then \ + $(SED) \ + -e '/^[[:space:]]*#[[:space:]]*DEPENDENCY CHART:/,/^$$/!d' \ + -e '/DEPENDENCY CHART/d' \ + -e '/^$$/d' \ + -e 's/^[[:space:]]*#//' \ + $(this_file) $(if $1,> '$1',); \ + else \ + $(ECHO) "Cannot determine the name of this makefile."; \ + fi +endef +# vim: noet sts=0 sw=8 ts=8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/README Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1 @@ +build with `make datacage-config-manual`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/content.tex Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,164 @@ +\section{Configuration of the Datacage} + +\subsection{Tasks and Recommendation types of the datacage} + +The datacage serves two purposes. +It handles automatic 'recommendations', which are instructions +sent by the client to add newly created artifacts to the collection. +From a user perspective, these artifacts mainly represent curves or data +points in the resulting diagrams. +The second task is to let the user add already existing artifacts (i.e. +previous calculations) or new artifacts with access to related data. + +Irrelevant of the type of elements (recommendations or user picked data) the +datacage can iterate over possible artifacts by accessing its own database. +Thus, to create a list of matching entries, database queries are used. + +\subsection{Structure of the datacage configuration file meta-data.conf} + +The datacages behaviour is defined in the file conf/meta-data.xml . + +In meta-data.xml, database queries are defined as \verb!<dc:statement>! elements, +for example +\begin{lstlisting} + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> +\end{lstlisting} + +As can be seen from the example, the datacage configuration file can maintain +its own stack of variables (\${river\_id} in above example). + +The database query will usually deliver one or many results, over which is +iterated using the \verb!<dc:elements>! elements. + +Information from this results can be used for two goals. +It can be taken as output, in which +case the client will either request the creation of these artifacts (considering +recommendations), or shown by the client in a the 'datacage widget', +the graphical representation of data which can be added in the current +context. The later is seen when the user clicks on the Datacage button in +a diagram. +Or information can be used to feed a second (or third...) database query. +Following above example: + +\begin{lstlisting} + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <additional> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <!-- ... --> +\end{lstlisting} + +In both cases, an \verb!<dc:elements>! element makes database queries available. +Also +note how the variables are defined in the first query and reused in the second +query (\$\{prot\_it\}). + +Any alement not prefixed with "dc" represents a (sub-) node in the resulting +tree. The client will display these nodes and maybe subnodes in the datacage +widget - \verb!<additional>! in above example. The elements name is translated by +the client. + +While iterating the final results, \verb!<dc:attributes>! have to be specified +to define how the artifact is to be created. + +\begin{lstlisting} + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + </column> + </dc:elements> +\end{lstlisting} + +The "name" attribute is what is to be displayed in the client, the "ids" are given +to the server and pass important information about the chosen data. +The "factory" is chosen according to the type of data displayed. + +So far, three other elements have not yet been mentioned: \verb!<dc:comment>!, +\verb!<dc:if>! and the \verb!<dc:when><dc:otherwise>! structure. +\verb!<dc:comment>! is an element to allow comments. Choose these over standard +\verb=<!-- -->= xml comments, because they are not transferred to the client. +\verb!<dc:if>! and \verb!<dc:when>! allow control (rather: definition) flow within +the configuration and work in analogy to the XSL-elements \verb!<xsl:if>! +and \verb!<xsl:when>!. + +When dealing with the behaviour specification of the datacage, multiple +interpretations for the term "context" are possible. +A \verb!<dc:context>! element essentially means a database binding. Thus each +query (\verb!<dc:statement>!) needs to be nested in its own context. +Furthermore, two types of databases with own bindings exist: +The "system" (default for \verb!<dc:context>!, \verb!<dc:context connection="system">!) +context allows queries related to the backend database with existing +data (e.g. measurements). +The "user" context (\verb!<dc:context connection="user">!) allows queries against +the database which stores information about already existing artifacts and +calculations. + +Another connotation for the term "context" is the situation from which +the datacage is queried. The standard case is a from the datacage widget. +When the user opens the datacage from the graphical client, this is done +from one of possible multiple diagrams. +When the datacage is queried, it gets as an argument the "out" of +the current artifact. The out corresponds to the diagram type. + +For example the inner block of + +\begin{lstlisting} + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')"> + <longitudinal_section> + <dc:call-macro name="annotations"/> + </longitudinal_section> + </dc:if> +\end{lstlisting} + +will only be executed if called from the datacage within a +longitudinal\_section diagram. + +In the given example another concept of the datacage configuration is +encountered: Macros. + +Macros help to avoid duplication of parts of the document. As the datacage +of some diagrams should include the same type of data, the same query should +be executed in multiple situations. + +Therefore a macro can be defined, like in + +\begin{lstlisting} + <dc:macro name="basedata_4_heightmarks-wq"> + <heightmarks> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 4 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <!-- ... --> + </dc:macro> +\end{lstlisting} + +and invoked from another location within the document, e.g. with + +\begin{lstlisting} + + <dc:call-macro name="basedata_4_heightmarks"/> +\end{lstlisting} +. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/datacage-config-manual.tex Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,199 @@ +\documentclass[12pt]{scrartcl} + +%---------------------------------------------- +% Load packages + +\usepackage{a4} +\usepackage{times} +\usepackage[latin1]{inputenc} +\usepackage{fancyhdr} +%\usepackage{german} +%\usepackage[marvosym]{eurofont} +%\usepackage[all, light]{draftcopy} +%\usepackage{supertabular} +%\usepackage{colortbl} +%\usepackage{epsf} +\usepackage{graphicx} +\usepackage{lastpage} +%\usepackage{proposal} +\usepackage{listings} +\usepackage[hyperindex=true, bookmarks=true, breaklinks=true, +colorlinks=true, linkcolor=red,bookmarksopen]{hyperref} + +%---------------------------------------------- +% Document DATE and VERSION +% set these values when releasing a new version + +\newcommand{\documentdate}{July 05th, 2012} +\newcommand{\documentversion}{1.0} +\newcommand{\documentrevision}{FIXME SVN REV} +\newcommand{\documentID}{datacage-config-manual.tex} +%---------------------------------------------- + +%---------------------------------------------- +% Document TITLE +\newcommand{\documenttitle}{FLYS 3.0 -- Configuration of the Datacage} + + +%---------------------------------------------- +% Some parameters for layouting + +\paperwidth=21cm +\hoffset=-0.54cm +\textwidth=17cm + +\paperheight=29.7cm +\voffset=-1.5cm +\topmargin=0cm +\headheight=1cm +\textheight=24cm + +\setcounter{secnumdepth}{4} +\setcounter{tocdepth}{4} + +%---------------------------------------------- + +\begin{document} + +\lstset{ % +language=sh, +basicstyle=\ttfamily, % the size of the fonts that are used for the code +numbers=left, % where to put the line-numbers +numberstyle=\footnotesize, % the size of the fonts that are used for the line-numbers +numbersep=5pt, % how far the line-numbers are from the code +% backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color} +showspaces=false, % show spaces adding particular underscores +showstringspaces=false, % underline spaces within strings +showtabs=false, % show tabs within strings adding particular underscores +frame=single, % adds a frame around the code +tabsize=2, % sets default tabsize to 2 spaces +captionpos=b, % sets the caption-position to bottom +breaklines=true, % sets automatic line breaking +breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace +title=\lstname, % show the filename of files included with \lstinputlisting; also try caption instead of title +escapeinside={\%*}{*)} % if you want to add a comment within your code +% morekeywords={*,...} % if you want to add more keywords to the set +} + +%----------------------------------- +% HEADER/FOOTER DEFINITION + +% for some pages latex switches back to pagestyle plain :-( +\fancypagestyle{plain}{% + \fancyhf{} % clear all header and footer fields + \fancyhead[LO,RE]{\footnotesize \documenttitle\\ \leftmark} + \fancyfoot[RO,LE]{\footnotesize Intevation GmbH} % Author + \fancyfoot[CO,CE]{\footnotesize \thepage/\pageref{LastPage}} + \fancyfoot[LO,RE]{\footnotesize \documentdate + \\\documentID} + \renewcommand{\footrulewidth}{0.4pt} +} + +% and now define pagestyle fancy +\fancyhead{} % clear all fields +\fancyhead[LO]{\footnotesize \documenttitle\\ \leftmark} + +\fancyfoot{}% clear all fields +\fancyfoot[RO]{\footnotesize Intevation GmbH} % Author +\fancyfoot[CO]{\footnotesize \thepage/\pageref{LastPage}} +\fancyfoot[LO]{\footnotesize \documentdate +\\\documentID} + +\renewcommand{\footrulewidth}{0.4pt} + +% +% END Header/Footer Definition +%----------------------------------- + +%---------------------------------------------- +% MACRO DEFINITION +% +% \Fig{figure}{lof text}{caption} : +% places 'figure' and +% writes 'caption' at the bottom with leading +% 'Abbildung figno:'. 'lof text' is added to the list of +% figures. +% Example: +% \Fig{\epsfxsize30mm \epsffile{x.eps}}{the x}{the x} +% +% \FigNoEntry{}{} : +% same as above, no entry in figures list +% +% \FigCaption{} : +% line with figure caption, setting figure +% counter and figures list +% +% \Tab{table}{lot text}{caption} : +% places 'table' and writes caption on top of the table +% with leading 'Tabelle tabno:'. 'lot text' is added to +% the list of tables. +%**************************************************************************** +% Figure makro for graphics continously enumerated. +% + +\newcounter{FigCnt} +\newcounter{TabCnt} + +\newcommand{\Fig}[3]% +{ + \refstepcounter{FigCnt} + \addcontentsline{lof}{figure}% + {\protect\numberline{\arabic{FigCnt}}{#2}} + \mbox{#1} + +\nopagebreak + {Abbildung \arabic{FigCnt}: #3} + +} + +\newcommand{\FigNoEntry}[2]% +{ + \refstepcounter{FigCnt} + \mbox{#1} + +\nopagebreak + {Abbildung \arabic{FigCnt}: #2} + +} + +\newcommand{\FigCaption}[1]% +{ + \refstepcounter{FigCnt} + \addcontentsline{lof}{figure}% + {\protect\numberline{\arabic{FigCnt}}{#1}} + + %{Figure \thesection.\arabic{FigCnt}: #1} +} + +\newcommand{\Tab}[3]% +{ + \refstepcounter{TabCnt} + \addcontentsline{lot}{figure}% + {\protect\numberline{\arabic{TabCnt}}{#2}} + {Tabelle \arabic{TabCnt}: #3} +\nopagebreak + #1 + +} + +\hyphenation{Intevation} +% end macro definition + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcounter{schritt} +\renewcommand{\theschritt}{\Roman{schritt}} +%\makeatletter\renewcommand{\p@schritt}{Abschnitt~\thesubsubsection~}\makeatother + +%----------------------------------- +% DOCUMENT SETTINGS +\pagestyle{fancy} +\setlength{\parindent}{0cm} +\setlength{\parskip}{5pt plus 2pt minus 1pt} + +% Start actual content here +\include{title} +\newpage +\tableofcontents +\include{content} +\end{document}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/figures/intevation-logo.eps Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1222 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%For: Frank Koormann,,, +%%CreationDate: Thu Mar 29 14:37:25 2001 +%%Title: intevation_logo-thin.eps +%%Creator: Sketch 0.6.8 +%%Pages: 1 +%%BoundingBox: 78 68 132 94 +%%Extensions: CMYK +%%DocumentSuppliedResources: (atend) +%%EndComments + +%%BeginProlog +%%BeginResource: procset Linux-Sketch-Procset 1.0 2 +/SketchDict 100 dict def +SketchDict begin +/bd { bind def } bind def +/x { exch } bd +/xd { exch def } bd +/PI 3.14159265358979323846264338327 def +/radgrad { 180 mul PI div } bd +/skstartmatrix matrix currentmatrix def +/tmpmat matrix def +/ISOLatin1Encoding dup where +{ pop pop } +{ [/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand +/quoteright /parenleft /parenright /asterisk /plus /comma /minus /period +/slash /zero /one /two /three /four /five /six /seven /eight /nine /colon +/semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J +/K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash +/bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i +/j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright +/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /dotlessi /grave /acute /circumflex /tilde /macron /breve +/dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek +/caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen +/registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu +/paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex +/Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex +/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve +/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute +/Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute +/acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute +/ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde +/ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave +/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def +} +ifelse +/arct dup where +{pop pop} +{ +/arct {arcto pop pop pop pop} bd +} +ifelse +/size 0 def +/fontname 0 def +/newfont 0 def +/sf { +/size xd +/fontname xd +fontname findfont +dup /Encoding get StandardEncoding eq +{ +dup +length dict /newfont xd +{ +1 index +/FID ne +{ newfont 3 1 roll put } +{ pop pop } +ifelse +} forall +newfont /Encoding ISOLatin1Encoding put +fontname newfont definefont +} +if +size scalefont setfont +} bd +/pusht {matrix currentmatrix} bd +/popt {setmatrix} bd +/pushc {gsave} bd +/popc {grestore} bd +/rgb {setrgbcolor} bd +/w { setlinewidth } bd +/j { setlinejoin } bd +/J { setlinecap } bd +/d { setdash } bd +/F { eofill } bd +/f { closepath F } bd +/S { +pusht +skstartmatrix setmatrix stroke +popt +} bd +/s { closepath S } bd +/m { moveto } bd +/l { lineto } bd +/c { curveto } bd +/txt { +/tmpmat tmpmat currentmatrix def +dup type /arraytype eq {concat} {translate} ifelse +0 0 m +tmpmat +} bd +/T {txt x show popt} bd +/P {txt x true charpath popt} bd +/TP {txt x dup show 0 0 m true charpath popt} bd +/C {newpath 0 360 arc} bd +/R { +2 copy m +x 2 index l +x 2 index x l +l +closepath +} bd +/ellipse { +dup type /arraytype eq +{ +pusht x concat +0 0 1.0 C +popt +} +{ +pusht 5 1 roll +4 -1 roll concat +newpath +dup 2 eq { +0 0 m +} if +3 1 roll +radgrad x +radgrad x +0 0 1 5 -2 roll +arc +0 ne { closepath } if +popt +} +ifelse +} bd +/radius1 0 def +/radius2 0 def +/factor 0 def +/rect { +dup type /arraytype eq +{ +pusht x concat +0 0 m 1 0 l 1 1 l 0 1 l closepath +popt +} +{ +/radius2 xd +/radius1 xd +pusht x concat +radius1 radius2 div 1 scale +0 radius2 m +0 1 radius2 1 radius2 arct +radius2 radius1 div +dup 1 1 index 0 radius2 arct +0 0 0 radius2 arct +0 0 0 1 radius2 arct +closepath +popt +} +ifelse +} bd +/buf 0 def +/width 0 def +/height 0 def +/skcimg { +/tmpmat tmpmat currentmatrix def +{ concat } if +/height xd +/width xd +/buf width 3 mul string def +width height scale +width height 8 +[width 0 0 height neg 0 height] +{ currentfile buf readhexstring pop } bind +false 3 colorimage +tmpmat setmatrix +} bd +/skgimg { +/tmpmat tmpmat currentmatrix def +{ concat } if +/height xd +/width xd +/buf width string def +width height scale +width height 8 +[width 0 0 height neg 0 height] +{ currentfile buf readhexstring pop } bind +image +tmpmat setmatrix +} bd +/rclip { +4 2 roll m +dup 0 x rlineto +x 0 rlineto +neg 0 x rlineto +closepath +clip +} bd +/skeps { +10 dict begin +/sk_state save def +concat +3 index neg 3 index neg translate +rclip +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin +10 setmiterlimit [ ] 0 setdash +newpath +/sk_dict_count countdictstack def +/sk_count count 1 sub def +userdict begin +/showpage { } def +/languagelevel where +{ +pop +languagelevel 1 ne +{ +false setstrokeadjust +false setoverprint +} if +} if +} bd +/skepsend { +count sk_count sub { pop } repeat +countdictstack sk_dict_count sub { end } repeat +sk_state restore +end +} bd +/gradidx 0 def +/gradient { +3 mul array +/gradidx 0 def +} bd +/$ { +3 index gradidx 5 -1 roll put +2 index gradidx 1 add 4 -1 roll put +1 index gradidx 2 add 3 -1 roll put +/gradidx gradidx 3 add def +} bd +/! { +3 +{ +dup dup gradidx dup 3 1 roll 3 sub get put +/gradidx gradidx 1 add def +} +repeat +} bd +/gradcolor { +3 mul dup 2 add 1 exch % idx 1 idx+2 +{ +1 index exch % array array i +get % array component +exch % component array +} +for +4 1 roll +} bd +/x0 0 def /y0 0 def /x1 0 def /y1 0 def +/left 0 def /right 0 def /top 0 def /bottom 0 def +/numcolors 0 def +/axial { +/y1 xd /x1 xd /y0 xd /x0 xd +dup length 3 idiv /numcolors xd +pusht exch % ctm array +x0 x1 ne y0 y1 ne or +{ +x0 y0 translate +[x1 x0 sub y1 y0 sub dup neg 2 index 0 0] concat +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +newpath +0 gradcolor rgb clippath f +0 1 numcolors 1 sub +{ +dup numcolors div +3 1 roll +gradcolor rgb +exch +bottom right top R f +} +for +} +if +pop +popt +} bd +/r0 0 def /r1 0 def /dr 0 def +/radial { +/r1 xd /r0 xd /y0 xd /x0 xd +/dr r1 r0 sub def +dup length 3 idiv /numcolors xd +pusht exch % ctm array +r0 r1 ne +{ +x0 y0 translate +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +newpath +dr 0 gt {numcolors 1 sub}{0} ifelse gradcolor rgb +clippath f +dr 0 gt {numcolors 1 sub -1 0} { 0 1 numcolors 1 sub} ifelse +{ +dup numcolors div dr mul r0 add +3 1 roll +gradcolor rgb +exch +0 0 3 -1 roll C f +} +for +} +if +pop +popt +} bd +/max { +2 copy lt {exch} if pop +} bd +/conical { +pusht 5 1 roll +3 1 roll /y0 xd /x0 xd +x0 y0 translate +radgrad rotate +dup length 3 idiv /numcolors xd +clippath flattenpath pathbbox newpath +4 { abs 4 1 roll} repeat +3 { max } repeat +2 mul +dup scale +0 gradcolor rgb +0 0 1 0 360 arc f +1 1 numcolors 1 sub +{ +dup numcolors div 180 mul +3 1 roll +gradcolor rgb +exch +0 0 moveto +0 0 1 4 -1 roll dup neg arc +closepath f +} +for +pop +popt +} bd +/XStep 0 def /YStep 0 def /imagedata 0 def /components 0 def +/tileimage2 { +exch 4 2 roll +/height xd +/width xd +mark +/components 2 index +/PatternType 1 +/PaintType 1 +/TilingType 1 +/BBox [0 0 width height] +/XStep width +/YStep height +/PaintProc { +begin +XStep YStep 8 +matrix +imagedata +false +components +colorimage +end +} +counttomark 2 div cvi dup dict begin +{ def } repeat +pop currentdict end +dup +/imagedata +4 -1 roll +width height mul mul string +currentfile exch readhexstring pop +put +exch +makepattern +setpattern +clippath +eofill +} bd +/tileimage1 { +concat +/components xd +/height xd +/width xd +/imagedata +currentfile +width height mul components mul string +readhexstring pop +def +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +left width div floor width mul +bottom height div floor height mul +translate +top bottom sub height div ceiling cvi +{ +gsave +right left sub width div ceiling cvi +{ +width height 8 matrix +components 1 eq +{ +{ imagedata } +image +} +{ +imagedata +false components +colorimage +} +ifelse +width 0 translate +} +repeat +grestore +0 height translate +} +repeat +} bd +/makepattern where +{ +pop +/tileimage /tileimage2 load def +} +{ +/tileimage /tileimage1 load def +} +ifelse +end +%%EndResource +%%EndProlog + +%%BeginSetup + +10.433 setmiterlimit +%%EndSetup + +%%Page: 1 1 +SketchDict begin +newpath +81.1479 90.3363 m +83.1262 89.4518 85.8962 89.4399 87.7755 90.732 c +88.4885 91.2221 89.1744 91.8548 89.1744 92.7451 c +89.3805 92.7446 89.5146 92.3854 89.7059 92.4617 c +90.3588 92.7216 91.0745 92.5334 91.5725 92.3012 c +91.8169 92.1873 92.0442 92.7366 92.3141 92.7358 c +92.4246 92.4106 93.2359 91.4866 93.2359 91.4372 c +95.3948 89.4748 99.2768 88.555 102.019 89.186 c +102.881 89.3844 110.268 92.0436 110.268 92.7837 c +110.735 92.6454 111.042 92.3763 111.801 92.3588 c +113.208 92.7366 l +114.425 92.9532 114.356 92.6862 114.93 92.6609 c +114.93 90.5837 114.005 87.8389 114.95 85.8136 c +115.043 85.6129 115.327 85.1931 115.474 85.044 c +119.365 81.1112 125.41 82.6691 129.868 84.5493 c +129.868 84.4181 130.124 84.2636 130.124 84.1323 c +130.124 83.9504 129.868 83.7916 129.868 83.6096 c +129.521 83.6096 129.294 83.4821 129.005 83.2726 c +126.771 81.6517 123.827 80.5003 121.756 78.5645 c +121.551 78.3735 121.558 78.1688 121.558 77.872 c +121.756 77.6246 122.036 77.2541 122.315 77.061 c +122.399 77.0029 122.564 76.8961 124.449 75.877 c +126.015 75.0309 127.68 74.6575 129.194 74.6604 c +129.194 74.475 129.046 74.2851 129.051 74.0807 c +129.052 74.0297 129.066 73.9744 129.086 73.9171 c +129.106 73.8599 129.132 73.8003 129.158 73.7411 c +129.183 73.6819 129.209 73.6226 129.227 73.5659 c +129.245 73.5087 129.255 73.4539 129.252 73.4038 c +129.238 73.1617 129.151 72.9814 129.076 72.7773 c +126.75 73.9407 124.211 75.0082 121.611 75.7449 c +120.232 76.1358 118.876 76.4938 117.501 76.7872 c +116.305 77.0426 113.981 77.2912 113.298 75.7452 c +112.578 74.1158 113.329 72.4451 113.544 70.8622 c +113.245 70.9989 113.04 71.6163 112.826 71.3291 c +112.556 70.799 l +112.21 71.5408 111.908 72.5375 111.698 73.3754 c +111.413 74.5161 110.852 75.2644 109.473 75.4597 c +107.323 75.7648 107.541 75.5249 106.808 75.0986 c +105.489 74.3316 104.447 72.6469 104.427 70.7633 c +104.103 70.8166 104.04 71.1029 103.715 71.1562 c +103.661 71.1361 103.594 71.1001 103.521 71.0624 c +103.448 71.0247 103.368 70.985 103.288 70.9575 c +103.209 70.9303 103.129 70.9147 103.056 70.9254 c +102.983 70.9359 102.916 70.9725 102.862 71.049 c +102.814 71.2619 102.513 71.4476 102.165 71.1947 c +101.229 70.799 l +101.108 71.1117 100.582 71.3382 100.316 71.5037 c +99.0659 72.2807 97.0528 71.5295 96.2781 70.5102 c +96.093 70.57 95.9079 70.6298 95.7225 70.6896 c +95.5289 70.7905 95.2567 70.9099 94.8114 70.6321 c +94.4917 70.5802 l +94.4917 70.8373 94.9407 70.8557 95.0994 71.1094 c +95.4787 71.7155 95.856 72.5599 96.434 73.236 c +97.4233 74.3934 98.3768 75.7545 97.6356 77.2578 c +97.415 77.7045 97.576 77.5078 96.6749 78.2941 c +96.1414 78.7598 95.3594 79.3486 94.7173 79.6468 c +91.9201 80.9465 88.4556 81.0936 85.1714 80.6681 c +83.4604 80.4467 81.7831 80.1902 80.3068 79.6031 c +80.2609 79.585 80.3031 79.5122 80.2535 79.5122 c +80.306 79.6936 80.6359 79.9461 80.4556 80.0496 c +80.2343 80.1389 80.2481 80.2886 80.2552 80.4833 c +80.2731 80.7971 l +80.4213 80.7971 80.3077 80.824 80.4554 80.8396 c +82.6332 81.0712 84.5517 81.7552 86.5887 82.4718 c +87.2231 82.6952 87.987 83.0019 88.527 83.452 c +88.8771 83.744 89.3216 84.2214 89.3216 84.6667 c +89.3216 85.0624 88.8949 85.959 88.6166 86.1815 c +86.4209 87.9381 80.8845 88.8736 80.8346 88.9422 c +80.7828 89.0136 l +80.7856 89.1103 81.0512 89.1729 81.1198 89.3575 c +81.1731 89.5006 81.0506 89.7858 81.1017 89.9232 c +81.1924 90.1679 81.2247 90.3363 81.1479 90.3363 c +closepath +gsave +0.9 0.9 0.9 rgb +F +grestore +0.9 0.9 0.9 rgb +0.215433 w +0 j +0 J +[] 0 d +S +newpath +108.203 84.2032 m +107.659 84.1536 106.67 83.9557 106.373 83.5107 c +106.324 83.5107 106.274 83.4611 106.274 83.4118 c +106.126 83.3622 106.027 82.9665 105.829 82.8675 c +105.829 82.1257 105.533 81.4828 106.126 80.8396 c +106.225 80.7407 l +106.423 80.6914 l +107.907 79.8999 109.341 79.9989 110.726 80.8892 c +110.776 80.9882 l +110.875 81.0375 111.072 81.3343 111.27 81.3343 c +111.27 81.8782 111.765 82.4225 111.418 83.115 c +111.32 83.3129 110.825 83.4611 110.825 83.659 c +110.726 83.659 110.132 84.0054 110.132 84.0547 c +109.935 84.0547 l +109.737 84.2525 108.401 84.2525 108.203 84.2032 c +closepath +gsave +0.8 0.8 0.8 rgb +F +grestore +0.7 0.7 0.7 rgb +0.566929 w +0 j +0 J +[] 0 d +S +newpath +129.218 74.6074 m +126.745 74.9042 123.636 75.6956 121.805 77.5256 c +121.657 77.6742 121.459 78.0203 121.459 78.2677 c +121.558 78.3171 l +121.558 78.3667 121.757 78.5634 121.805 78.6139 c +123.135 79.9966 125.128 80.6576 126.673 81.7561 c +128.047 82.7323 129.427 83.5107 129.67 83.5107 c +129.775 83.5629 130.033 83.615 130.115 83.659 c +129.109 72.8173 m +127.427 73.3119 125.912 74.363 124.229 74.9042 c +121.542 75.7684 l +120.528 76.0947 119.51 76.4014 118.523 76.5599 c +116.741 76.8465 115.229 77.6229 113.743 76.2892 c +112.805 75.4467 113.006 74.657 113.006 73.4205 c +113.121 72.9094 113.569 71.2846 113.569 70.7888 c +112.54 70.8024 m +111.897 72.0885 111.86 74.2406 110.585 75.1462 c +109.981 75.576 107.912 75.6808 107.214 75.4484 c +106.724 75.2851 106.373 74.7559 106.027 74.4095 c +105.087 73.4698 104.431 72.0363 104.431 70.7009 c +101.387 70.7216 m +100.435 71.9918 98.2462 72.4301 97.0247 71.1409 c +96.8801 71.0068 96.6052 70.7772 96.0915 70.388 c +94.588 70.6593 m +95.3302 71.0054 95.6213 71.8212 95.9603 72.5171 c +96.561 73.7499 98.571 75.6363 97.6602 77.1169 c +97.3518 77.6183 l +97.063 78.124 95.8361 79.0019 95.7069 79.1312 c +95.509 79.329 94.9892 79.5357 94.7496 79.6525 c +90.7346 81.6135 86.2429 80.9354 82.0379 80.1471 c +81.4945 80.0454 80.7354 79.496 80.1915 79.496 c +80.855 88.9875 m +81.4486 88.839 81.943 88.619 82.5326 88.4566 c +83.9216 88.0751 85.6935 87.8542 86.9841 87.1708 c +87.3753 86.9639 87.8251 86.5772 88.2209 86.3794 c +88.9627 86.0333 89.3091 85.2418 89.2595 84.4008 c +89.2595 84.2032 88.8592 83.7624 88.7155 83.6096 c +88.0678 82.9214 86.6839 82.482 85.7972 82.175 c +84.1118 81.5919 82.1369 80.7407 80.3068 80.7407 c +80.2575 80.6914 l +81.2564 90.302 m +81.7865 90.031 81.8707 90.1115 82.3007 89.9334 c +83.7949 89.3152 85.8009 89.932 87.1823 90.5344 c +88.1222 90.944 89.2116 91.7442 89.2116 92.8407 c +92.2753 92.7032 m +92.9678 91.6646 93.7564 90.8221 94.8982 90.2869 c +95.3392 90.0803 95.9901 89.7098 96.481 89.5944 c +98.5129 89.1165 100.233 88.7908 102.318 89.1987 c +102.511 89.2367 102.58 89.2282 103.109 89.3966 c +105.253 90.0783 107.678 91.2292 109.638 92.3148 c +109.697 92.3474 110.336 92.8129 110.352 92.8129 c +114.93 92.7352 m +114.815 91.7541 114.609 90.9627 114.61 90.427 c +114.611 88.8645 114.327 87.8086 114.634 86.6268 c +115.198 84.4504 118.458 82.8638 119.975 82.7193 c +123.178 82.4137 126.158 83.2958 129.076 84.3515 c +129.123 84.3682 129.274 84.4008 129.373 84.4008 c +129.423 84.4997 129.818 84.6483 129.967 84.6483 c +0.8 0.8 0.8 rgb +1 j +1 J +S +newpath +81.6246 86.9766 m +82.6698 86.9766 l +82.6698 79.2655 l +81.6246 79.2655 l +81.6246 86.9766 l +closepath +84.0446 82.4667 m +84.0446 82.7598 84.0959 83.0368 84.1988 83.297 c +84.3014 83.5575 84.4553 83.8013 84.6606 84.0286 c +84.8734 84.2486 85.1226 84.4155 85.4086 84.5292 c +85.6946 84.6429 86.0209 84.6996 86.3877 84.6996 c +86.4464 84.6996 86.5104 84.6959 86.5802 84.6885 c +86.6499 84.6811 86.725 84.6704 86.8058 84.6556 c +86.8863 84.6409 86.9688 84.6227 87.0533 84.6006 c +87.1375 84.5785 87.2236 84.5493 87.3118 84.5125 c +87.4657 84.4467 87.6123 84.3622 87.7517 84.2596 c +87.8909 84.157 88.0267 84.0323 88.1588 83.8857 c +88.2906 83.7463 88.3898 83.5739 88.4559 83.3687 c +88.5216 83.1632 88.5548 82.9285 88.5548 82.6646 c +88.5548 82.6572 88.5548 82.6481 88.5548 82.6371 c +88.5548 82.626 88.5548 82.6133 88.5548 82.5985 c +88.5548 82.5911 88.5548 82.5821 88.5548 82.571 c +88.5548 82.56 88.5548 82.5472 88.5548 82.5325 c +88.5548 79.2655 l +87.5097 79.2655 l +87.5097 82.3786 l +87.5097 82.5398 87.4858 82.6994 87.4382 82.857 c +87.3906 83.0146 87.3192 83.1632 87.2236 83.3026 c +87.1284 83.4492 87.0037 83.5592 86.8497 83.6326 c +86.6958 83.706 86.5124 83.7426 86.2998 83.7426 c +86.1017 83.7426 85.9276 83.7097 85.7771 83.6437 c +85.6269 83.5776 85.4968 83.4787 85.3868 83.3466 c +85.2768 83.2145 85.1906 83.0733 85.1283 82.9231 c +85.0659 82.7729 85.0237 82.6133 85.0016 82.4446 c +85.0016 79.2655 l +84.0446 79.2655 l +84.0446 82.4667 l +closepath +89.6767 85.8436 m +90.7108 85.8436 l +90.7108 84.5456 l +92.7126 84.5456 l +92.7126 83.5997 l +90.7108 83.5997 l +90.7108 80.9156 l +90.7108 80.813 90.7179 80.7211 90.7326 80.6406 c +90.7474 80.5598 90.7695 80.483 90.7987 80.4096 c +90.8279 80.3362 90.8922 80.2832 90.9912 80.25 c +91.0901 80.2171 91.2276 80.2007 91.4036 80.2007 c +92.6248 80.2225 l +92.6248 79.2655 l +91.3268 79.2655 l +91.3194 79.2655 91.312 79.2655 91.3047 79.2655 c +91.2973 79.2655 91.2899 79.2655 91.2826 79.2655 c +91.2755 79.2655 91.2698 79.2655 91.2661 79.2655 c +91.2624 79.2655 91.2571 79.2619 91.2497 79.2545 c +91.2423 79.2545 91.2349 79.2545 91.2276 79.2545 c +91.2205 79.2545 91.2131 79.2545 91.2057 79.2545 c +91.1984 79.2545 91.193 79.2545 91.1893 79.2545 c +91.1856 79.2545 91.18 79.2545 91.1726 79.2545 c +90.9234 79.2545 90.7071 79.2913 90.5237 79.3645 c +90.3403 79.4379 90.1901 79.5516 90.0727 79.7055 c +89.9554 79.8597 89.8655 80.0247 89.8032 80.2007 c +89.7408 80.3764 89.7023 80.5598 89.6878 80.7506 c +89.6804 80.7654 89.6767 80.7818 89.6767 80.7999 c +89.6767 80.8184 89.6767 80.8385 89.6767 80.8606 c +89.6767 80.8753 89.6767 80.8918 89.6767 80.9099 c +89.6767 80.9283 89.6767 80.9485 89.6767 80.9706 c +89.6767 80.9927 l +89.6767 85.8436 l +closepath +96.7829 83.1595 m +96.7682 83.1669 96.7534 83.1762 96.7387 83.187 c +96.7242 83.198 96.7095 83.2145 96.6948 83.2366 c +96.68 83.2513 96.6636 83.2695 96.6454 83.2916 c +96.627 83.3137 96.6069 83.3355 96.5848 83.3576 c +96.5629 83.3724 96.5388 83.3888 96.5133 83.407 c +96.4875 83.4254 96.4637 83.4455 96.4419 83.4676 c +96.4124 83.4824 96.3832 83.4988 96.3537 83.5172 c +96.3246 83.5354 96.2914 83.5518 96.2548 83.5666 c +96.1814 83.6031 96.0952 83.6289 95.9963 83.6437 c +95.8974 83.6584 95.7854 83.6655 95.6607 83.6655 c +95.3747 83.6655 95.1235 83.6142 94.9072 83.5116 c +94.6909 83.4089 94.5095 83.2587 94.3627 83.0606 c +94.2161 82.8627 94.1062 82.6535 94.0327 82.4335 c +93.9593 82.2136 93.9228 81.9862 93.9228 81.7515 c +93.9228 81.7442 93.9228 81.7368 93.9228 81.7297 c +93.9228 81.7186 l +93.9228 81.5058 93.9613 81.3025 94.0384 81.1081 c +94.1152 80.9136 94.2272 80.7285 94.3737 80.5525 c +94.5206 80.3764 94.702 80.2446 94.9183 80.1565 c +95.1346 80.0686 95.382 80.0247 95.6607 80.0247 c +95.9614 80.0247 96.2126 80.0592 96.4144 80.129 c +96.616 80.1987 96.7682 80.3033 96.8708 80.4425 c +96.9734 80.5893 97.0669 80.7617 97.1514 80.9595 c +97.2356 81.1577 97.3107 81.3813 97.3768 81.6305 c +97.3768 81.6415 l +97.3878 81.6526 l +97.3878 81.6637 l +98.3448 81.6087 l +98.3448 81.5939 98.3448 81.5812 98.3448 81.5701 c +98.3448 81.5591 98.3485 81.55 98.3559 81.5426 c +98.3559 81.5279 98.3559 81.5168 98.3559 81.5094 c +98.3559 81.5024 98.3559 81.4913 98.3559 81.4766 c +98.3559 81.4692 98.3559 81.4601 98.3559 81.4491 c +98.3559 81.438 98.3595 81.4289 98.3669 81.4216 c +98.3669 81.4068 98.3669 81.3958 98.3669 81.3887 c +98.3669 81.3813 98.3669 81.374 98.3669 81.3666 c +98.3669 81.3079 98.3632 81.2475 98.3559 81.1852 c +98.3485 81.1228 98.3374 81.0585 98.323 80.9927 c +98.3156 80.9632 98.3063 80.9303 98.2952 80.8935 c +98.2844 80.8569 98.2751 80.824 98.2677 80.7946 c +98.2532 80.758 98.2402 80.7231 98.2294 80.69 c +98.2184 80.6571 98.2056 80.6222 98.1909 80.5856 c +98.1027 80.4022 97.9854 80.2225 97.8388 80.0465 c +97.6923 79.8705 97.5126 79.7055 97.3 79.5516 c +97.0944 79.3976 96.8543 79.282 96.5794 79.2052 c +96.3044 79.1281 95.9983 79.0895 95.6607 79.0895 c +95.272 79.0895 94.9129 79.1502 94.5827 79.2709 c +94.2527 79.392 93.9559 79.5774 93.6917 79.8265 c +93.4205 80.0833 93.2189 80.3711 93.0868 80.69 c +92.9547 81.0091 92.8887 81.3629 92.8887 81.7515 c +92.8887 82.1623 92.9437 82.5254 93.0536 82.8406 c +93.1636 83.1558 93.3289 83.4274 93.5489 83.6547 c +93.7688 83.882 93.9999 84.0688 94.2417 84.2157 c +94.4837 84.3622 94.7369 84.4685 95.0008 84.5346 c +95.0303 84.542 95.0577 84.5473 95.0833 84.551 c +95.1091 84.5547 95.1366 84.5604 95.1657 84.5675 c +95.1952 84.5675 95.2227 84.5695 95.2482 84.5731 c +95.274 84.5768 95.3015 84.5822 95.3307 84.5896 c +95.3894 84.5969 95.4464 84.6023 95.5014 84.606 c +95.5564 84.6097 95.6094 84.6117 95.6607 84.6117 c +95.9614 84.6117 96.2421 84.5695 96.5023 84.485 c +96.7628 84.4008 97.0029 84.2744 97.2229 84.1057 c +97.4354 83.937 97.6279 83.75 97.8003 83.5447 c +97.9726 83.3392 98.1248 83.1192 98.2569 82.8845 c +94.6158 80.9156 l +94.1867 81.6855 l +96.7829 83.1595 l +closepath +99.6431 84.5456 m +101.282 80.3875 l +102.756 84.5456 l +103.889 84.5456 l +102.063 79.7826 l +102.019 79.6726 101.969 79.5791 101.914 79.502 c +101.859 79.4251 101.799 79.3608 101.733 79.3095 c +101.667 79.2655 101.599 79.229 101.53 79.1995 c +101.46 79.1703 101.385 79.1519 101.304 79.1445 c +101.297 79.1445 101.291 79.1445 101.287 79.1445 c +101.284 79.1445 101.278 79.1445 101.271 79.1445 c +101.264 79.1445 101.256 79.1445 101.249 79.1445 c +101.168 79.1445 101.09 79.1556 101.012 79.1777 c +100.935 79.1995 100.857 79.2327 100.776 79.2766 c +100.703 79.3353 100.637 79.403 100.578 79.4801 c +100.519 79.5569 100.468 79.6505 100.424 79.7605 c +98.5101 84.5456 l +99.6431 84.5456 l +closepath +108.388 82.3015 m +108.388 82.463 108.357 82.6223 108.294 82.7802 c +108.232 82.9378 108.139 83.0864 108.014 83.2255 c +107.889 83.3724 107.713 83.4824 107.486 83.5555 c +107.259 83.6289 106.984 83.6655 106.661 83.6655 c +106.609 83.6655 106.556 83.6618 106.501 83.6547 c +106.447 83.6473 106.386 83.6363 106.32 83.6215 c +106.254 83.6142 106.188 83.5997 106.122 83.5776 c +106.056 83.5555 105.99 83.5263 105.924 83.4897 c +105.807 83.4381 105.693 83.3667 105.583 83.2751 c +105.473 83.1833 105.367 83.0753 105.264 82.9506 c +105.169 82.8332 105.092 82.6884 105.033 82.516 c +104.974 82.3437 104.938 82.1475 104.923 81.9276 c +104.923 81.6342 104.963 81.3793 105.044 81.1631 c +105.125 80.9468 105.245 80.7654 105.407 80.6185 c +105.576 80.4793 105.75 80.3674 105.929 80.2832 c +106.109 80.1987 106.298 80.1454 106.496 80.1236 c +106.503 80.1236 106.513 80.1236 106.523 80.1236 c +106.534 80.1236 106.544 80.1236 106.551 80.1236 c +106.566 80.1162 106.578 80.1125 106.589 80.1125 c +106.6 80.1125 106.609 80.1125 106.617 80.1125 c +106.632 80.1125 106.643 80.1125 106.65 80.1125 c +106.657 80.1125 106.668 80.1125 106.683 80.1125 c +106.69 80.1125 106.699 80.1125 106.71 80.1125 c +106.721 80.1125 106.731 80.1125 106.738 80.1125 c +106.826 80.1125 106.909 80.1179 106.985 80.129 c +107.062 80.14 107.138 80.1602 107.211 80.1896 c +107.248 80.2041 107.282 80.2188 107.315 80.2336 c +107.348 80.2483 107.383 80.2628 107.42 80.2775 c +107.449 80.2996 107.482 80.3214 107.519 80.3436 c +107.556 80.3657 107.589 80.3912 107.618 80.4207 c +107.655 80.4425 107.689 80.47 107.722 80.5032 c +107.756 80.536 107.79 80.5672 107.827 80.5967 c +107.864 80.6333 107.9 80.6681 107.937 80.701 c +107.974 80.7342 108.01 80.7688 108.047 80.8056 c +108.047 79.6066 l +108.04 79.5918 108.032 79.5808 108.025 79.5737 c +108.025 79.5626 l +107.937 79.5039 107.845 79.4506 107.75 79.403 c +107.655 79.3554 107.556 79.3132 107.453 79.2766 c +107.35 79.2471 107.225 79.2233 107.079 79.2052 c +106.932 79.1867 106.764 79.1777 106.573 79.1777 c +106.566 79.1777 106.56 79.1777 106.556 79.1777 c +106.553 79.1777 106.547 79.1777 106.54 79.1777 c +106.533 79.1777 106.522 79.1777 106.507 79.1777 c +106.5 79.1777 106.492 79.1777 106.485 79.1777 c +106.478 79.1777 106.47 79.1777 106.463 79.1777 c +106.456 79.1777 106.45 79.1777 106.447 79.1777 c +106.443 79.1777 106.437 79.1777 106.43 79.1777 c +106.092 79.1777 105.779 79.238 105.49 79.3591 c +105.2 79.4801 104.934 79.6652 104.692 79.9147 c +104.45 80.1712 104.268 80.4663 104.147 80.7999 c +104.026 81.1339 103.966 81.5094 103.966 81.9276 c +103.966 82.2944 104.025 82.6354 104.142 82.9506 c +104.259 83.2658 104.435 83.5555 104.67 83.8197 c +104.904 84.0836 105.194 84.2817 105.539 84.4135 c +105.884 84.5456 106.283 84.6117 106.738 84.6117 c +107.17 84.6117 107.556 84.553 107.893 84.4357 c +108.23 84.3183 108.513 84.1423 108.74 83.9076 c +108.975 83.6729 109.149 83.4254 109.262 83.1652 c +109.376 82.9047 109.433 82.6354 109.433 82.3564 c +109.433 79.2655 l +108.388 79.2655 l +108.388 82.3015 l +closepath +110.467 85.8436 m +111.501 85.8436 l +111.501 84.5456 l +113.503 84.5456 l +113.503 83.5997 l +111.501 83.5997 l +111.501 80.9156 l +111.501 80.813 111.508 80.7211 111.523 80.6406 c +111.538 80.5598 111.56 80.483 111.589 80.4096 c +111.618 80.3362 111.683 80.2832 111.782 80.25 c +111.881 80.2171 112.018 80.2007 112.194 80.2007 c +113.415 80.2225 l +113.415 79.2655 l +112.117 79.2655 l +112.11 79.2655 112.102 79.2655 112.095 79.2655 c +112.088 79.2655 112.08 79.2655 112.073 79.2655 c +112.066 79.2655 112.06 79.2655 112.057 79.2655 c +112.053 79.2655 112.047 79.2619 112.04 79.2545 c +112.033 79.2545 112.025 79.2545 112.018 79.2545 c +112.011 79.2545 112.004 79.2545 111.996 79.2545 c +111.989 79.2545 111.983 79.2545 111.98 79.2545 c +111.976 79.2545 111.97 79.2545 111.963 79.2545 c +111.714 79.2545 111.498 79.2913 111.314 79.3645 c +111.131 79.4379 110.981 79.5516 110.863 79.7055 c +110.746 79.8597 110.656 80.0247 110.594 80.2007 c +110.531 80.3764 110.493 80.5598 110.478 80.7506 c +110.471 80.7654 110.467 80.7818 110.467 80.7999 c +110.467 80.8184 110.467 80.8385 110.467 80.8606 c +110.467 80.8753 110.467 80.8918 110.467 80.9099 c +110.467 80.9283 110.467 80.9485 110.467 80.9706 c +110.467 80.9927 l +110.467 85.8436 l +closepath +114.449 84.5456 m +115.406 84.5456 l +115.406 79.2655 l +114.449 79.2655 l +114.449 84.5456 l +closepath +114.372 85.7665 m +114.372 85.8473 114.387 85.9224 114.416 85.9922 c +114.446 86.0619 114.493 86.1223 114.559 86.1736 c +114.618 86.2175 114.682 86.2524 114.752 86.2782 c +114.821 86.3037 114.893 86.3167 114.966 86.3167 c +115.047 86.3167 115.12 86.3057 115.186 86.2836 c +115.252 86.2617 115.318 86.2249 115.384 86.1736 c +115.45 86.1223 115.5 86.0619 115.533 85.9922 c +115.566 85.9224 115.582 85.8399 115.582 85.7447 c +115.582 85.6492 115.566 85.565 115.533 85.4916 c +115.5 85.4181 115.454 85.3561 115.395 85.3045 c +115.329 85.2532 115.263 85.2166 115.197 85.1945 c +115.131 85.1727 115.062 85.1616 114.988 85.1616 c +114.915 85.1542 114.842 85.1616 114.768 85.1837 c +114.695 85.2055 114.625 85.2424 114.559 85.2937 c +114.493 85.345 114.446 85.4091 114.416 85.4862 c +114.387 85.563 114.372 85.6492 114.372 85.7447 c +114.372 85.7665 l +closepath +116.792 82.0375 m +116.792 82.4409 116.862 82.804 117.001 83.1266 c +117.14 83.4492 117.346 83.7315 117.617 83.9736 c +117.896 84.2157 118.191 84.3971 118.503 84.5181 c +118.814 84.6392 119.143 84.6996 119.487 84.6996 c +119.502 84.6996 119.518 84.6996 119.537 84.6996 c +119.555 84.6996 119.571 84.6996 119.586 84.6996 c +119.601 84.6922 119.617 84.6885 119.636 84.6885 c +119.654 84.6885 119.674 84.6885 119.696 84.6885 c +119.711 84.6885 119.727 84.6885 119.746 84.6885 c +119.764 84.6885 119.784 84.6885 119.806 84.6885 c +119.821 84.6811 119.837 84.6777 119.856 84.6777 c +119.874 84.6777 119.89 84.6777 119.905 84.6777 c +120.199 84.6335 120.479 84.5473 120.747 84.4192 c +121.014 84.2908 121.273 84.1202 121.522 83.9076 c +121.764 83.6876 121.947 83.4126 122.072 83.0827 c +122.197 82.7527 122.259 82.3675 122.259 81.9276 c +122.259 81.8984 122.259 81.8689 122.259 81.8397 c +122.259 81.8102 122.256 81.7847 122.248 81.7626 c +122.248 81.7331 122.246 81.7039 122.243 81.6747 c +122.239 81.6452 122.237 81.616 122.237 81.5865 c +122.23 81.5279 122.221 81.4692 122.21 81.4105 c +122.199 81.3518 122.186 81.2932 122.171 81.2345 c +122.105 80.9706 122.004 80.7194 121.869 80.481 c +121.733 80.2426 121.559 80.0173 121.346 79.8044 c +121.141 79.5918 120.895 79.4342 120.609 79.3316 c +120.323 79.229 120.004 79.1777 119.652 79.1777 c +119.153 79.1777 118.723 79.2454 118.36 79.3809 c +117.997 79.5167 117.701 79.7239 117.474 80.0025 c +117.247 80.2812 117.076 80.5893 116.962 80.9266 c +116.849 81.264 116.792 81.6268 116.792 82.0154 c +116.792 82.0375 l +closepath +117.837 82.0375 m +117.837 81.9789 117.837 81.9259 117.837 81.878 c +117.837 81.8303 117.841 81.781 117.848 81.7297 c +117.855 81.6781 117.865 81.6288 117.876 81.5812 c +117.887 81.5335 117.896 81.4839 117.903 81.4326 c +117.94 81.2713 117.999 81.1134 118.079 80.9595 c +118.16 80.8056 118.259 80.6588 118.376 80.5196 c +118.501 80.3801 118.655 80.2775 118.838 80.2115 c +119.022 80.1454 119.238 80.1125 119.487 80.1125 c +119.722 80.1125 119.942 80.1454 120.147 80.2115 c +120.352 80.2775 120.54 80.3764 120.708 80.5085 c +120.877 80.6406 121.003 80.8331 121.088 81.086 c +121.172 81.3391 121.214 81.6489 121.214 82.0154 c +121.214 82.2722 121.178 82.505 121.104 82.7142 c +121.031 82.9231 120.921 83.1082 120.774 83.2695 c +120.627 83.4237 120.446 83.541 120.23 83.6215 c +120.013 83.7023 119.766 83.7426 119.487 83.7426 c +119.223 83.7426 118.996 83.7077 118.805 83.638 c +118.615 83.5685 118.457 83.4603 118.332 83.3137 c +118.207 83.1742 118.107 83.024 118.03 82.8627 c +117.953 82.7011 117.899 82.5362 117.87 82.3675 c +117.863 82.3383 117.855 82.3088 117.848 82.2796 c +117.841 82.2501 117.837 82.2209 117.837 82.1915 c +117.837 82.1623 117.837 82.1328 117.837 82.1036 c +117.837 82.0741 117.837 82.0449 117.837 82.0154 c +117.837 82.0375 l +closepath +123.205 82.4667 m +123.205 82.7598 123.257 83.0368 123.359 83.297 c +123.462 83.5575 123.616 83.8013 123.821 84.0286 c +124.034 84.2486 124.283 84.4155 124.569 84.5292 c +124.855 84.6429 125.182 84.6996 125.548 84.6996 c +125.607 84.6996 125.671 84.6959 125.741 84.6885 c +125.811 84.6811 125.886 84.6704 125.966 84.6556 c +126.047 84.6409 126.129 84.6227 126.214 84.6006 c +126.298 84.5785 126.384 84.5493 126.472 84.5125 c +126.626 84.4467 126.773 84.3622 126.912 84.2596 c +127.052 84.157 127.187 84.0323 127.319 83.8857 c +127.451 83.7463 127.55 83.5739 127.616 83.3687 c +127.682 83.1632 127.715 82.9285 127.715 82.6646 c +127.715 82.6572 127.715 82.6481 127.715 82.6371 c +127.715 82.626 127.715 82.6133 127.715 82.5985 c +127.715 82.5911 127.715 82.5821 127.715 82.571 c +127.715 82.56 127.715 82.5472 127.715 82.5325 c +127.715 79.2655 l +126.67 79.2655 l +126.67 82.3786 l +126.67 82.5398 126.646 82.6994 126.599 82.857 c +126.551 83.0146 126.48 83.1632 126.384 83.3026 c +126.289 83.4492 126.164 83.5592 126.01 83.6326 c +125.856 83.706 125.673 83.7426 125.46 83.7426 c +125.262 83.7426 125.088 83.7097 124.938 83.6437 c +124.788 83.5776 124.657 83.4787 124.547 83.3466 c +124.437 83.2145 124.351 83.0733 124.289 82.9231 c +124.227 82.7729 124.184 82.6133 124.162 82.4446 c +124.162 79.2655 l +123.205 79.2655 l +123.205 82.4667 l +closepath +0 0 0 rgb +F +newpath +113.172 76.343 m +113.172 76.6049 113.208 76.8397 113.279 77.0474 c +113.35 77.2549 113.455 77.4355 113.593 77.5889 c +113.736 77.7422 113.883 77.8732 114.037 77.9817 c +114.19 78.0903 114.351 78.1745 114.519 78.2343 c +114.549 78.2456 114.58 78.2558 114.612 78.2652 c +114.644 78.2746 114.676 78.2848 114.71 78.2961 c +114.74 78.3035 114.771 78.3111 114.803 78.3185 c +114.835 78.3259 114.865 78.3315 114.895 78.3352 c +114.959 78.3465 115.02 78.3551 115.078 78.3607 c +115.136 78.3661 115.193 78.3689 115.249 78.3689 c +115.402 78.3689 115.55 78.3539 115.692 78.3242 c +115.835 78.2941 115.969 78.2513 116.096 78.1952 c +116.223 78.1391 116.349 78.0659 116.472 77.9761 c +116.596 77.8865 116.718 77.7816 116.837 77.662 c +116.484 77.2745 l +116.469 77.2821 116.454 77.2915 116.441 77.3026 c +116.428 77.3139 116.414 77.3269 116.4 77.3419 c +116.392 77.3493 116.384 77.357 116.377 77.3643 c +116.369 77.372 116.362 77.3794 116.354 77.3867 c +116.343 77.3944 116.334 77.4018 116.326 77.4094 c +116.319 77.4168 116.311 77.4242 116.304 77.4318 c +116.237 77.4879 116.164 77.5412 116.085 77.5917 c +116.007 77.6421 115.922 77.6917 115.833 77.7405 c +115.743 77.7853 115.649 77.8199 115.552 77.8443 c +115.455 77.8686 115.354 77.8808 115.249 77.8808 c +115.021 77.8808 114.819 77.8479 114.645 77.7825 c +114.472 77.717 114.325 77.6189 114.205 77.4879 c +114.089 77.3607 113.995 77.2252 113.921 77.0809 c +113.849 76.9369 113.799 76.7864 113.773 76.6293 c +113.769 76.603 113.764 76.5777 113.759 76.5534 c +113.753 76.5293 113.75 76.5037 113.75 76.4777 c +113.747 76.4516 113.745 76.4264 113.745 76.402 c +113.745 76.3776 113.745 76.3541 113.745 76.3317 c +113.745 76.1446 113.776 75.964 113.837 75.7903 c +113.899 75.6162 113.992 75.4507 114.115 75.2934 c +114.239 75.1363 114.395 75.0156 114.584 74.9314 c +114.773 74.8472 114.994 74.7996 115.249 74.7885 c +115.253 74.7885 115.255 74.7885 115.257 74.7885 c +115.259 74.7885 115.262 74.7885 115.266 74.7885 c +115.269 74.7885 115.273 74.7885 115.277 74.7885 c +115.281 74.7885 115.284 74.7885 115.288 74.7885 c +115.296 74.7885 115.301 74.7885 115.305 74.7885 c +115.309 74.7885 115.312 74.7885 115.313 74.7885 c +115.315 74.7885 115.318 74.7885 115.322 74.7885 c +115.49 74.7845 115.644 74.8072 115.782 74.8557 c +115.92 74.9044 116.042 74.9793 116.147 75.0802 c +116.255 75.1774 116.346 75.2814 116.419 75.3917 c +116.492 75.502 116.549 75.6171 116.59 75.737 c +116.601 75.7667 116.612 75.7957 116.621 75.8237 c +116.631 75.8518 116.637 75.879 116.641 75.9054 c +116.644 75.9201 116.647 75.9343 116.649 75.9473 c +116.651 75.9603 116.652 75.9745 116.652 75.9895 c +116.656 76.0006 116.659 76.0128 116.66 76.0258 c +116.662 76.0389 116.663 76.053 116.663 76.0681 c +115.294 76.0791 l +115.294 76.6123 l +117.236 76.6123 l +117.236 76.1242 l +117.213 75.8285 117.148 75.5695 117.039 75.3469 c +116.931 75.1241 116.781 74.9342 116.59 74.7772 c +116.396 74.6201 116.187 74.5031 115.964 74.4262 c +115.742 74.3497 115.503 74.3114 115.249 74.3114 c +114.95 74.3114 114.676 74.3571 114.429 74.4489 c +114.183 74.5405 113.964 74.6816 113.773 74.8727 c +113.582 75.0595 113.436 75.2758 113.335 75.5207 c +113.234 75.7659 113.18 76.0363 113.172 76.3317 c +113.172 76.343 l +closepath +117.724 76.2138 m +117.724 76.33 117.746 76.4394 117.791 76.5423 c +117.836 76.6452 117.905 76.7396 117.999 76.8258 c +118.092 76.9117 118.201 76.9763 118.324 77.0194 c +118.448 77.0622 118.586 77.0837 118.74 77.0837 c +118.848 77.0837 118.944 77.0755 119.026 77.0585 c +119.108 77.0418 119.175 77.0182 119.228 76.9885 c +119.28 76.9584 119.329 76.9219 119.374 76.8791 c +119.419 76.836 119.458 76.7864 119.492 76.7302 c +119.525 76.775 119.567 76.8173 119.615 76.8564 c +119.664 76.8958 119.722 76.9341 119.789 76.9715 c +119.857 77.0089 119.931 77.0369 120.014 77.0557 c +120.096 77.0744 120.188 77.0837 120.289 77.0837 c +120.416 77.0837 120.536 77.0661 120.648 77.0304 c +120.76 76.995 120.865 76.9397 120.962 76.8649 c +121.059 76.7937 121.133 76.7124 121.184 76.6208 c +121.234 76.5293 121.261 76.4272 121.265 76.315 c +121.265 76.3113 121.265 76.3084 121.265 76.3065 c +121.265 76.3048 121.265 76.3019 121.265 76.298 c +121.265 76.2943 121.265 76.2914 121.265 76.2897 c +121.265 76.2878 121.265 76.2849 121.265 76.2812 c +121.261 76.2775 121.26 76.2747 121.26 76.2727 c +121.26 76.271 121.26 76.2682 121.26 76.2645 c +121.26 76.2605 121.26 76.258 121.26 76.256 c +121.26 76.254 121.26 76.2512 121.26 76.2475 c +121.26 74.3562 l +120.771 74.3562 l +120.771 76.0791 l +120.771 76.0754 120.771 76.0746 120.771 76.0763 c +120.771 76.0783 120.773 76.0791 120.777 76.0791 c +120.777 76.0828 120.777 76.0856 120.777 76.0876 c +120.777 76.0896 120.777 76.0922 120.777 76.0961 c +120.777 76.1035 120.777 76.11 120.777 76.1157 c +120.777 76.1214 120.777 76.1259 120.777 76.1296 c +120.777 76.1409 120.776 76.1523 120.774 76.1633 c +120.772 76.1746 120.769 76.1877 120.766 76.2027 c +120.762 76.2138 120.759 76.226 120.757 76.2393 c +120.756 76.2523 120.753 76.2662 120.749 76.2812 c +120.734 76.326 120.712 76.3691 120.682 76.4102 c +120.651 76.4516 120.616 76.4907 120.575 76.5281 c +120.534 76.5655 120.489 76.5936 120.44 76.6123 c +120.392 76.631 120.341 76.6404 120.289 76.6404 c +120.221 76.6404 120.159 76.6282 120.101 76.6038 c +120.043 76.5797 119.989 76.5432 119.941 76.4944 c +119.892 76.4459 119.854 76.3943 119.826 76.3402 c +119.798 76.286 119.778 76.2288 119.767 76.169 c +119.763 76.1616 119.76 76.1531 119.758 76.1437 c +119.756 76.1344 119.755 76.1259 119.755 76.1185 c +119.755 76.1072 119.755 76.0978 119.755 76.0905 c +119.755 76.0828 119.755 76.0754 119.755 76.0681 c +119.755 74.3562 l +119.273 74.3562 l +119.273 76.0343 l +119.273 76.1165 119.262 76.1934 119.239 76.2645 c +119.217 76.3354 119.183 76.4008 119.138 76.4609 c +119.093 76.5208 119.037 76.5655 118.97 76.5956 c +118.903 76.6254 118.826 76.6404 118.74 76.6404 c +118.631 76.6293 118.541 76.6049 118.47 76.5675 c +118.399 76.5301 118.347 76.4797 118.313 76.4159 c +118.279 76.3524 118.254 76.2849 118.237 76.2138 c +118.22 76.1429 118.212 76.0698 118.212 75.9949 c +118.212 75.9912 118.212 75.9876 118.212 75.9839 c +118.212 75.9782 l +118.212 74.3562 l +117.724 74.3562 l +117.724 76.2138 l +closepath +122.23 78.2456 m +122.23 75.7256 l +122.23 75.576 122.249 75.4422 122.286 75.3242 c +122.324 75.2066 122.378 75.1026 122.449 75.0127 c +122.524 74.9231 122.613 74.8557 122.716 74.8109 c +122.819 74.7658 122.936 74.7434 123.067 74.7434 c +123.19 74.7434 123.3 74.7613 123.398 74.7967 c +123.495 74.8324 123.579 74.8857 123.65 74.9566 c +123.718 75.0277 123.774 75.1026 123.819 75.1811 c +123.864 75.2599 123.897 75.3401 123.92 75.4226 c +123.927 75.4413 123.932 75.4609 123.934 75.4816 c +123.936 75.502 123.939 75.5235 123.942 75.5459 c +123.946 75.5686 123.949 75.5899 123.95 75.6105 c +123.952 75.6312 123.953 75.6508 123.953 75.6695 c +123.953 75.8192 123.934 75.9501 123.894 76.0624 c +123.855 76.1746 123.798 76.2662 123.723 76.3374 c +123.649 76.4122 123.569 76.4711 123.485 76.5142 c +123.401 76.5573 123.313 76.5843 123.224 76.5956 c +123.213 76.5956 123.202 76.5956 123.193 76.5956 c +123.184 76.5956 123.175 76.5956 123.168 76.5956 c +123.164 76.5956 123.159 76.5956 123.154 76.5956 c +123.148 76.5956 123.143 76.5973 123.14 76.6013 c +123.132 76.6013 123.126 76.6013 123.123 76.6013 c +123.119 76.6013 123.115 76.6013 123.112 76.6013 c +123.056 76.6013 123.003 76.5973 122.954 76.5899 c +122.906 76.5826 122.861 76.5712 122.82 76.5562 c +122.779 76.5412 122.738 76.5253 122.699 76.5086 c +122.66 76.4918 122.62 76.474 122.578 76.4553 c +122.573 76.4496 l +122.567 76.4496 l +122.56 76.4459 122.552 76.4422 122.545 76.4383 c +122.537 76.4346 122.532 76.4329 122.528 76.4329 c +122.52 76.4289 122.514 76.4252 122.508 76.4215 c +122.503 76.4179 122.496 76.4142 122.489 76.4102 c +122.474 76.4065 122.46 76.402 122.446 76.3963 c +122.433 76.3906 122.419 76.3841 122.404 76.3768 c +122.404 76.8762 l +122.446 76.8949 122.486 76.9136 122.525 76.9323 c +122.564 76.9511 122.605 76.9678 122.646 76.9828 c +122.687 76.9978 122.728 77.0109 122.769 77.0222 c +122.81 77.0333 122.853 77.0426 122.898 77.0503 c +122.917 77.054 122.936 77.0568 122.957 77.0585 c +122.978 77.0605 122.999 77.0633 123.022 77.067 c +123.033 77.067 123.043 77.067 123.053 77.067 c +123.062 77.067 123.072 77.069 123.084 77.0727 c +123.091 77.0727 123.1 77.0727 123.112 77.0727 c +123.123 77.0727 123.134 77.0727 123.145 77.0727 c +123.321 77.0727 123.486 77.0435 123.639 76.9856 c +123.793 76.9275 123.937 76.8388 124.071 76.7189 c +124.206 76.603 124.308 76.4646 124.377 76.3036 c +124.446 76.1429 124.481 75.9615 124.481 75.7594 c +124.481 75.5723 124.451 75.3926 124.391 75.2205 c +124.331 75.0484 124.242 74.8838 124.122 74.7267 c +124.006 74.5694 123.859 74.4534 123.681 74.3786 c +123.503 74.3038 123.298 74.2664 123.067 74.2664 c +122.835 74.2664 122.633 74.3029 122.461 74.3758 c +122.288 74.4489 122.146 74.56 122.034 74.7097 c +121.922 74.8633 121.837 75.0269 121.781 75.2009 c +121.725 75.375 121.697 75.5609 121.697 75.7594 c +121.697 78.2456 l +122.23 78.2456 l +closepath +124.969 78.2904 m +125.497 78.2904 l +125.497 76.6965 l +127.181 76.6965 l +127.181 78.2904 l +127.708 78.2904 l +127.708 74.3562 l +127.181 74.3562 l +127.181 76.169 l +125.497 76.169 l +125.497 74.3562 l +124.969 74.3562 l +124.969 78.2904 l +closepath +F +%%PageTrailer +showpage +%%Trailer +end +%%DocumentSuppliedResources: procset Linux-Sketch-Procset 1.0 2 +%%EOF
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage-config-manual/title.tex Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,51 @@ +%----------------------------------- +% TITLE PAGE + +% FIXME BSH Logo + +\begin{figure}[ht] + \begin{minipage}[b]{0.5\linewidth} + \centering + \includegraphics[scale=0.75]{figures/bsh_logo} \\ + {\tt http://www.bsh.de/en}\\[4.0cm] + \end{minipage} + \begin{minipage}[b]{0.5\linewidth} + \centering + \includegraphics[width=0.75\textwidth]{figures/intevation-logo} + {\tt http://intevation.de/geospatial}\\[2.0cm] + \end{minipage} +\end{figure} + + \vspace{4cm} + + { + \sffamily\large + Documentation FLYS 3.0 + + \vspace{1cm} + { + \bfseries\huge + Documentation of the Datacage + } + + \vspace{1cm} + Version \documentversion~-~Date: \documentdate + +% Revision \documentrevision + } + + \vspace{4cm} + + \thispagestyle{empty} + + \vfill + + \begin{flushleft} + Authors:\\ + Felix Wolfsteller$<$felix.wolfsteller@intevation.de$>$\\ + {\bf Intevation GmbH},\\ + Neuer Graben 17, 49074 Osnabrück, Germany\\ + Tel: ++49 541 33 50 83 - 0 \\ + http://www.intevation.net/geospatial + + \end{flushleft}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/datacage.txt Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,148 @@ +This document describes how the datacage configuration works, from a user +perspective. Some rather technical details are omitted and mechanisms +simplified. + +The datacages behaviour is defined in the file conf/meta-data.xml . + +The datacage serves two purposes. +It handles automatic 'recommendations', which are instructions +sent by the client to add newly created artifacts to the collection. +From a user perspective, these artifacts mainly represent curves or data +points in the resulting diagrams. +The second task is to let the user add already existing artifacts (i.e. +previous calculations) or new artifacts with access to related data. + +Irrelevant of the type of elements (recommendations or user picked data) the +datacage can iterate over possible artifacts by accessing its own database. +Thus, to create a list of matching entries, database queries are used. + +In meta-data.xml, database queries are defined as <dc:statement> elements, +for example + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> + +As can be seen from the example, the datacage configuration file can maintain +its own stack of variables (${river_id} in above example). + +The database query will usually deliver one or many results, over which is +iterated using the <dc:elements> elements. + +Information from this results can be used for two goals. +It can be taken as output, in which +case the client will either request the creation of these artifacts (considering +recommendations), or shown by the client in a the 'datacage widget', +the graphical representation of data which can be added in the current +context. The later is seen when the user clicks on the Datacage button in +a diagram. +Or information can be used to feed a second (or third...) database query. +Following above example: + + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 1 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <additional> + <dc:attribute name="name" value="${prot_description}"/> + <dc:context> + <dc:statement> + SELECT id AS prot_column_id, + name AS prot_column_name, + position AS prot_rel_pos + FROM wst_columns WHERE wst_id = ${prot_id} + ORDER by position + </dc:statement> + <!-- ... --> + +In both cases, an <dc:elements> element makes database queries available. +Also +note how the variables are defined in the first query and reused in the second +query (${prot_it}). + +Any alement not prefixed with "dc" represents a (sub-) node in the resulting +tree. The client will display these nodes and maybe subnodes in the datacage +widget - <additional> in above example. The elements name is translated by +the client. + +While iterating the final results, <dc:attributes> have to be specified +to define how the artifact is to be created. + + <dc:elements> + <column> + <dc:attribute name="name" value="${prot_column_name}"/> + <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/> + <dc:attribute name="factory" value="staticwkms"/> + </column> + </dc:elements> + +The "name" attribute is what is to be displayed in the client, the "ids" are given +to the server and pass important information about the chosen data. +The "factory" is chosen according to the type of data displayed. + +So far, three other elements have not yet been mentioned: <dc:comment>, +<dc:if> and the <dc:when><dc:otherwise> structure. +<dc:comment> is an element to allow comments. Choose these over standard +<!-- --> xml comments, because they are not transferred to the client. +<dc:if> and <dc:when> allow control (rather: definition) flow within +the configuration and work in analogy to the XSL-elements <xsl:if> +and <xsl:when>. + +When dealing with the behaviour specification of the datacage, multiple +interpretations for the term "context" are possible. +A <dc:context> element essentially means a database binding. Thus each +query (<dc:statement>) needs to be nested in its own context. +Furthermore, two types of databases with own bindings exist: +The "system" (default for <dc:context>, <dc:context connection="system">) +context allows queries related to the backend database with existing +data (e.g. measurements). +The "user" context (<dc:context connection="user">) allows queries against +the database which stores information about already existing artifacts and +calculations. + +Another connotation for the term "context" is the situation from which +the datacage is queried. The standard case is a from the datacage widget. +When the user opens the datacage from the graphical client, this is done +from one of possible multiple diagrams. +When the datacage is queried, it gets as an argument the "out" of +the current artifact. The out corresponds to the diagram type. + +For example the inner block of + + <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')"> + <longitudinal_section> + <dc:call-macro name="annotations"/> + </longitudinal_section> + </dc:if> + +will only be executed if called from the datacage within a +longitudinal_section diagram. + +In the given example another concept of the datacage configuration is +encountered: Macros. + +Macros help to avoid duplication of parts of the document. As the datacage +of some diagrams should include the same type of data, the same query should +be executed in multiple situations. + +Therefore a macro can be defined, like in + + <dc:macro name="basedata_4_heightmarks-wq"> + <heightmarks> + <dc:context> + <dc:statement> + SELECT id AS prot_id, + description AS prot_description + FROM wsts WHERE kind = 4 AND river_id = ${river_id} + </dc:statement> + <dc:elements> + <!-- ... --> + </dc:macro> + +and invoked from another location within the document, e.g. with + + <dc:call-macro name="basedata_4_heightmarks"/> +.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/dbconnection.include Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,2 @@ +CONNECTIONTYPE postgis +CONNECTION "dbname='flys3' host=127.0.0.1 port=5432 user='flys' password='flys' sslmode=disable"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/elbe-mapfile.map Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +MAP + NAME "Elbe" + STATUS ON + SIZE 600 400 + MAXSIZE 4000 + EXTENT 3590790.616790 5648985.748203 3868521.325854 5922665.254118 + UNITS DD + #FONTSET "fontset.txt" + IMAGECOLOR 255 255 255 + PROJECTION + "init=epsg:31466" + END + + + OUTPUTFORMAT + NAME agg + DRIVER AGG/PNG + IMAGEMODE RGB + END + + CONFIG "MS_ERRORFILE" "logs/flys-elbe-wms.log" + DEBUG 5 + + WEB + METADATA + "wms_title" "FLYS-3.0 WMS (ELBE)" + "wms_onlineresource" "http://czech-republic.atlas.intevation.de/cgi-bin/elbe-wms" + "wms_accessconstraints" "none" + "wms_fees" "none" + "wms_addresstype" "postal" + "wms_address" "Any Street" + "wms_city" "Any City" + "wms_stateorprovince" "Any state" + "wms_postcode" "My Postalcode" + "wms_country" "Any Country" + "wms_contactperson" "Any Person" + "wms_contactorganization" "Any Orga" + "wms_contactelectronicmailaddress" "any-email@example.com" + "wms_contactvoicetelephone" "Any's telephone number" + "wms_srs" "EPSG:31466 EPSG:4326" + "wms_feature_info_mime_type" "text/html" + "ows_enable_request" "*" + END + END + + LAYER + NAME riveraxis + EXTENT 3590790.616790 5648985.748203 3868521.325854 5922665.254118 + DEBUG 5 + + METADATA + "wms_title" "River Axis" + END + + TYPE LINE + STATUS ON + INCLUDE "dbconnection.include" + DATA 'geom FROM "river_axes" USING UNIQUE id USING srid=31466' + FILTER "river_id='6'" + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "riveraxis" + STYLE + SIZE 5 + COLOR "#000000" + END + END + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/fontset.txt Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,5 @@ +# LiberationsSans weist eine metrische Identitaet zu Arial auf und ist unter +# einer freien Lizenz (modifizierte GPL 2) verfuegbar. +# Quelle: http://de.wikipedia.org/wiki/Arial + +LiberationSans-Italic /usr/share/fonts/truetype/LiberationSans-Italic.ttf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/mosel-mapfile.map Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,301 @@ +MAP + NAME "Mosel" + STATUS ON + SIZE 600 400 + MAXSIZE 4000 + EXTENT 2457864.326387 5297459.306295 2634771.191263 5586961.449130 + UNITS DD + FONTSET "fontset.txt" + SYMBOLSET './symbols/symbols.sym' + IMAGECOLOR 255 255 255 + PROJECTION + "init=epsg:31466" + END + + + OUTPUTFORMAT + NAME agg + DRIVER AGG/PNG + IMAGEMODE RGB + END + + CONFIG "MS_ERRORFILE" "logs/flys-mosel-wms.log" + DEBUG 5 + + WEB + METADATA + "wms_title" "FLYS-3.0 WMS (SAAR)" + "wms_onlineresource" "http://czech-republic.atlas.intevation.de/cgi-bin/saar-wms" + "wms_accessconstraints" "none" + "wms_fees" "none" + "wms_addresstype" "postal" + "wms_address" "Any Street" + "wms_city" "Any City" + "wms_stateorprovince" "Any state" + "wms_postcode" "My Postalcode" + "wms_country" "Any Country" + "wms_contactperson" "Any Person" + "wms_contactorganization" "Any Orga" + "wms_contactelectronicmailaddress" "any-email@example.com" + "wms_contactvoicetelephone" "Any's telephone number" + "wms_srs" "EPSG:31466 EPSG:4326" + "wms_feature_info_mime_type" "text/html" + "ows_enable_request" "*" + END + END + + LAYER + NAME catchment + EXTENT 2457864.326387 5297459.306295 2634771.191263 5586961.449130 + DEBUG 0 + + METADATA + "wms_title" "catchment" + END + + TYPE POLYGON + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM catchment USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "catchment" + STYLE + COLOR "#000080" + OUTLINECOLOR "#000000" + END + END + END + LAYER + NAME km + GROUP km + EXTENT 2525910.000000 5481666.000000 2614362.250000 5582403.000000 + DEBUG 0 + DUMP TRUE + + METADATA + "wms_title" "km" + END + + TYPE POINT + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes_km USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "km" + STYLE + COLOR "#ff0000" + SYMBOL 'square' + SIZE 5 + END + END + END + + LAYER + NAME km_annotation + GROUP km + EXTENT 2525910.000000 5481666.000000 2614362.250000 5582403.000000 + DEBUG 5 + DUMP TRUE + + METADATA + "wms_title" "km_annotation" + END + + TYPE ANNOTATION + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes_km USING SRID 31466" + FILTER 'river_id=2' + LABELITEM km + + MAXSCALE 25000 + + CLASS + LABEL + ANGLE auto + SIZE 10 + COLOR "#000000" + TYPE truetype + FONT LiberationSans-Italic + POSITION ur + OFFSET 2 2 + END + END + END + + LAYER + NAME buildings + Extent 2526389.654387 5492305.031511 2612653.500000 5582427.500000 + DEBUG 0 + + METADATA + "wms_title" "buildings (Bauwerke/Wehre)" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM buildings USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "buildings" + STYLE + COLOR "#ff2222" + END + END + END + LAYER + NAME fixpoints + EXTENT 2525789.640000 5481448.110000 2614324.201153 5582705.474713 + DEBUG 0 + + METADATA + "wms_title" "fixpoints (Geodaesie/Festpunkte)" + END + + TYPE POINT + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM fixpoints USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "fixpoints" + STYLE + COLOR "#ffff00" + SYMBOL 'square' + SIZE 6 + END + END + END + LAYER + NAME riveraxis + EXTENT 2525866.883066 5480800.000000 2614283.382914 5582578.641600 + DEBUG 0 + + METADATA + "wms_title" "River Axes" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "riveraxes" + STYLE + COLOR "#0000ff" + END + END + END + + LAYER + NAME qps + EXTENT 2525526.058176 5481412.836939 2614739.057487 5582746.998120 + DEBUG 0 + + METADATA + "wms_title" "QPS (CrossSectionTracks)" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM cross_section_tracks USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + MAXSCALEDENOM 100000 + + CLASS + NAME "qps" + STYLE + COLOR "#0000ff" + END + END + END + + LAYER + NAME hws + EXTENT 2531846.270698 5501745.060309 2580199.261246 5535383.855597 + DEBUG 0 + + METADATA + "wms_title" "HWS" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM hws USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "hws" + STYLE + COLOR "#ff2222" + END + END + END + LAYER + NAME floodplain + EXTENT 2583046.060000 5556912.223213 2614325.275661 5582743.883699 + DEBUG 0 + + METADATA + "wms_title" "floodplain (Hydr. Grenzen/Talaue)" + END + + TYPE POLYGON + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM floodplain USING SRID 31466" + FILTER 'river_id=2' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "floodplain" + STYLE + COLOR "#800080" + OUTLINECOLOR "#000080" + END + END + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/oracle_dbconnection.include Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,2 @@ +CONNECTIONTYPE oraclespatial +CONNECTION "flys3/flys3@localhost"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/saar-mapfile.map Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,301 @@ +MAP + NAME "Saar" + STATUS ON + SIZE 600 400 + MAXSIZE 4000 + EXTENT 2539488.036000 5450928.892000 2575486.407000 5507352.839000 + UNITS DD + FONTSET "fontset.txt" + SYMBOLSET './symbols/symbols.sym' + IMAGECOLOR 255 255 255 + PROJECTION + "init=epsg:31466" + END + + + OUTPUTFORMAT + NAME agg + DRIVER AGG/PNG + IMAGEMODE RGB + END + + CONFIG "MS_ERRORFILE" "logs/flys-saar-wms.log" + DEBUG 0 + + WEB + METADATA + "wms_title" "FLYS-3.0 WMS (SAAR)" + "wms_onlineresource" "http://czech-republic.atlas.intevation.de/cgi-bin/saar-wms" + "wms_accessconstraints" "none" + "wms_fees" "none" + "wms_addresstype" "postal" + "wms_address" "Any Street" + "wms_city" "Any City" + "wms_stateorprovince" "Any state" + "wms_postcode" "My Postalcode" + "wms_country" "Any Country" + "wms_contactperson" "Any Person" + "wms_contactorganization" "Any Orga" + "wms_contactelectronicmailaddress" "any-email@example.com" + "wms_contactvoicetelephone" "Any's telephone number" + "wms_srs" "EPSG:31466 EPSG:4326" + "wms_feature_info_mime_type" "text/html" + "ows_enable_request" "*" + END + END + + LAYER + NAME catchment + EXTENT 2520667.897954 5376316.575645 2634771.191263 5508288.005707 + DEBUG 0 + + METADATA + "wms_title" "catchment" + END + + TYPE POLYGON + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM catchment USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "catchment" + STYLE + COLOR "#000080" + OUTLINECOLOR "#000000" + END + END + END + LAYER + NAME km + GROUP km + EXTENT 2539489.068000 5450953.000500 2575482.527500 5507278.634500 + DEBUG 0 + DUMP TRUE + + METADATA + "wms_title" "km" + END + + TYPE POINT + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes_km USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "km" + STYLE + COLOR "#ff0000" + SYMBOL 'square' + SIZE 5 + END + END + END + + LAYER + NAME km_annotation + GROUP km + EXTENT 2539489.068000 5450953.000500 2575482.527500 5507278.634500 + DEBUG 5 + DUMP TRUE + + METADATA + "wms_title" "km_annotation" + END + + TYPE ANNOTATION + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes_km USING SRID 31466" + FILTER 'river_id=1' + LABELITEM km + + MAXSCALE 25000 + + CLASS + LABEL + ANGLE auto + SIZE 10 + COLOR "#000000" + TYPE truetype + FONT LiberationSans-Italic + POSITION ur + OFFSET 2 2 + END + END + END + + LAYER + NAME buildings + EXTENT 2540544.253718 5456266.217464 2567747.834199 5502557.982120 + DEBUG 0 + + METADATA + "wms_title" "buildings (Bauwerke/Wehre)" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM buildings USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "buildings" + STYLE + COLOR "#ff2222" + END + END + END + LAYER + NAME fixpoints + EXTENT 2539388.036000 5450896.688000 2575586.296000 5507370.606000 + DEBUG 0 + + METADATA + "wms_title" "fixpoints (Geodaesie/Festpunkte)" + END + + TYPE POINT + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM fixpoints USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "fixpoints" + STYLE + COLOR "#ffff00" + SYMBOL 'square' + SIZE 6 + END + END + END + LAYER + NAME riveraxes + EXTENT 2539488.036000 5450928.892000 2575486.407000 5507352.839000 + DEBUG 0 + + METADATA + "wms_title" "River Axes" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM river_axes USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "riveraxes" + STYLE + COLOR "#0000ff" + END + END + END + + LAYER + NAME qps + EXTENT 2539289.724000 5450852.896743 2576589.878311 5507289.656000 + DEBUG 0 + + METADATA + "wms_title" "QPS (CrossSectionTracks)" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM cross_section_tracks USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + MAXSCALEDENOM 100000 + + CLASS + NAME "qps" + STYLE + COLOR "#0000ff" + END + END + END + + LAYER + NAME hws + EXTENT 2539778.101933 5456638.161347 2567463.841704 5500605.745332 + DEBUG 0 + + METADATA + "wms_title" "HWS" + END + + TYPE LINE + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM hws USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "hws" + STYLE + COLOR "#ff2222" + END + END + END + LAYER + NAME floodplain + EXTENT 2539343.776823 5451397.340027 2576021.009478 5507230.640000 + DEBUG 0 + + METADATA + "wms_title" "floodplain (Hydr. Grenzen/Talaue)" + END + + TYPE POLYGON + STATUS ON + INCLUDE "oracle_dbconnection.include" + DATA "GEOM FROM floodplain USING SRID 31466" + FILTER 'river_id=1' + + PROJECTION + "init=epsg:31466" + END + + CLASS + NAME "floodplain" + STYLE + COLOR "#800080" + OUTLINECOLOR "#000080" + END + END + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/doc/mapserver/symbols/symbols.sym Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,22 @@ +SYMBOLSET +SYMBOL + NAME 'point' + TYPE ELLIPSE + POINTS + 1 1 + END + FILLED TRUE +END +SYMBOL + NAME "square" + TYPE VECTOR + POINTS + 0 0 + 0 1 + 1 1 + 1 0 + 0 0 + END + FILLED TRUE +END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/pom.xml Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,170 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>de.intevation.flys.artifacts</groupId> + <artifactId>flys-artifacts</artifactId> + <version>1.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>flys-artifacts</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.0.2</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.8.1</version> + <configuration> + <show>private</show> + <nohelp>true</nohelp> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>net.sf.ehcache</groupId> + <artifactId>ehcache-core</artifactId> + <version>2.4.2</version> + </dependency> + <dependency> + <groupId>jfree</groupId> + <artifactId>jfreechart</artifactId> + <version>1.0.13</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>trove</groupId> + <artifactId>trove</artifactId> + <version>1.1-beta-5</version> + </dependency> + <dependency> + <groupId>net.sf.opencsv</groupId> + <artifactId>opencsv</artifactId> + <version>2.0</version> + </dependency> + <dependency> + <groupId>de.intevation.bsh.artifact-database</groupId> + <artifactId>artifact-database</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>de.intevation.artifacts.common</groupId> + <artifactId>artifacts-common</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>de.intevation.flys</groupId> + <artifactId>flys-backend</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>jfree</groupId> + <artifactId>jfreechart</artifactId> + <version>1.0.13</version> + </dependency> + <dependency> + <groupId>org.apache.xmlgraphics</groupId> + <artifactId>batik-dom</artifactId> + <version>1.7</version> + </dependency> + <dependency> + <groupId>org.apache.xmlgraphics</groupId> + <artifactId>batik-svggen</artifactId> + <version>1.7</version> + </dependency> + <dependency> + <groupId>com.lowagie</groupId> + <artifactId>itext</artifactId> + <version>2.1.7</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-math</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>1.3.158</version> + </dependency> + <dependency> + <groupId>commons-dbcp</groupId> + <artifactId>commons-dbcp</artifactId> + <version>1.2.2</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt-shapefile</artifactId> + <version>2.7.2</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt-epsg-wkt</artifactId> + <version>2.7.2</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt-geojson</artifactId> + <version>2.7.2</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt-swing</artifactId> + <version>2.7.2</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20090211</version> + </dependency> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.7</version> + </dependency> + <dependency> + <groupId>net.sf.jasperreports</groupId> + <artifactId>jasperreports</artifactId> + <version>4.5.0</version> + </dependency> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-all</artifactId> + <version>1.6.0</version> + </dependency> + </dependencies> + <repositories> + <repository> + <id>jboss-repo2</id> + <name>JBoss repo2</name> + <url>http://repository.jboss.org/nexus/content/groups/public/</url> + </repository> + <repository> + <id>gt2.repo</id> + <name>GeoTools2 Repository including JTS</name> + <url>http://download.osgeo.org/webdav/geotools</url> + </repository> + </repositories> +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,213 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.state.StateEngine; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.context.FLYSContext; + +import de.intevation.flys.utils.FLYSUtils; + +/** + * Artifact to access names of Points Of Interest along a segment of a river. + */ +public class AnnotationArtifact extends StaticFLYSArtifact { + + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(AnnotationArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "annotation"; + + /** Get river, setup Facets. */ + @Override + protected void initialize(Artifact artifact, Object context, + CallMeta meta) { + logger.debug("AnnotationArtifact.initialize, id: " + + artifact.identifier()); + + FLYSArtifact flys = (FLYSArtifact) artifact; + importData(flys, "river"); + + List<Facet> fs = new ArrayList<Facet>(); + + // TODO Add CallMeta (duplicate TODO in RiverAxisArtifact.java). + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + + if (!fs.isEmpty()) { + logger.debug("Facets to add in AnnotationsArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in AnnotationsArtifact.initialize ."); + } + } + + + public double[] getDistance() { + /** TODO In initialize(), access maximal range of river (via + * AnnotationFactory) instead of overriding getDistance, + * important for diagram generation. */ + return new double[] {0f, 1000f}; + } + + + /** + * Create the description of this AnnotationArtifact-instance. + * + * @param data Some data. + * @param context The CallContext. + * + * @return the description of this artifact. + */ + @Override + public Document describe(Document data, CallContext context) { + logger.debug("Describe: the current state is: " + getCurrentStateId()); + + if (logger.isDebugEnabled()) { + dumpArtifact(); + } + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine stateEngine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + Document description = XMLUtils.newDocument(); + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + description, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = ProtocolUtils.createRootNode(creator); + description.appendChild(root); + + State current = getCurrentState(context); + + ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash()); + ProtocolUtils.appendState(creator, root, current); + + Element name = ProtocolUtils.createArtNode( + creator, "name", + new String[] { "value" }, + new String[] { getName() }); + + Element outs = ProtocolUtils.createArtNode( + creator, "outputmodes", null, null); + appendOutputModes(description, outs, context); + + root.appendChild(name); + root.appendChild(outs); + + return description; + } + + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + public String getName() { + return ARTIFACT_NAME; + } + + + /** + * Append outputmode elements to given document. + * + * @param doc Document to add outputmodes to. + * @param outs Element to add outputmode elements to. + * @param context The given CallContext (mostly for internationalization). + */ + //@Override + protected void appendOutputModes( + Document doc, + Element outs, + CallContext context) + { + List<String> stateIds = getPreviousStateIds(); + + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + for (String stateId: stateIds) { + logger.debug("Append output modes for state: " + stateId); + DefaultState state = (DefaultState) engine.getState(stateId); + + List<Output> list = state.getOutputs(); + if (list == null || list.isEmpty()) { + logger.debug("-> No output modes for this state."); + continue; + } + + List<Facet> fs = facets.get(stateId); + if (fs == null || fs.isEmpty()) { + logger.debug("No facets found."); + continue; + } + + logger.debug("Found " + fs.size() + " facets in previous states."); + + List<Output> generated = generateOutputs(list, fs); + + ProtocolUtils.appendOutputModes(doc, outs, generated); + } + + try { + DefaultState cur = (DefaultState) getCurrentState(context); + if (cur.validate(this)) { + List<Output> list = cur.getOutputs(); + if (list != null && list.size() > 0) { + logger.debug( + "Append output modes for state: " + cur.getID()); + + List<Facet> fs = facets.get(cur.getID()); + if (fs != null && fs.size() > 0) { + List<Output> generated = generateOutputs(list, fs); + + logger.debug("Found " + fs.size() + " current facets."); + if (!generated.isEmpty()) { + ProtocolUtils.appendOutputModes( + doc, outs, generated); + } + else{ + logger.debug("Cannot append output to generated document."); + } + } + else { + logger.debug("No facets found for the current state."); + } + } + } + } + catch (IllegalArgumentException iae) { + // state is not valid, so we do not append its outputs. + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AreaArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,180 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.AreaFacet; + + +import de.intevation.flys.artifacts.states.AreaCreationState; +import de.intevation.flys.artifacts.states.StaticState; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + + +/** + * Artifact describing the area between two WKms. + */ +public class AreaArtifact extends StaticFLYSArtifact { + + /** Name of Artifact. */ + public static final String AREA_ARTIFACT_NAME = "area_artifact"; + + /** Dataitem: Facet name. Facets with this name will be created (important + * to not have the area calculated in e.g. a CrossSection to be shown in + * LongitudinalSection. */ + protected static final String FACET_NAME = "area.facet"; + + /** Name of state. */ + public static final String STATIC_STATE_NAME = "state.area_artifact"; + + /** data item name to access upper curve. */ + protected static final String AREA_CURVE_OVER = "area.curve_over"; + + /** data item name to access lower curve. */ + protected static final String AREA_CURVE_UNDER = "area.curve_under"; + + /** data item name to access whether or not paint over and under. */ + protected static final String AREA_BETWEEN = "area.between"; + + /** Name of state. */ + protected static final String AREA_NAME = "area.name"; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(AreaArtifact.class); + + + /** Return given name. */ + @Override + public String getName() { + return AREA_ARTIFACT_NAME; + } + + + /** Store ids, create an AreaFacet. */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.info("AreaArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + + // TODO yet unused. + String ids = getDatacageIDValue(data); + + // TODO this facet will be remodeled during next feed. + List<Facet> fs = new ArrayList<Facet>(); + fs.add(new AreaFacet(0, "", "TODO: I am an AreaFacet")); + + AreaCreationState state = (AreaCreationState) getCurrentState(context); + + if (!fs.isEmpty()) { + facets.put(getCurrentStateId(), fs); + } + } + + // TODO Data is not cached in this way. + + /** Do not copy data from daddyfact. */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + // do nothing + } + + + /** + * Get name of facets to create. + */ + public String getFacetName() { + return getDataAsString(FACET_NAME); + } + + + /** + * Get dataprovider key for the 'lower' curve (we got that information fed + * from the client and store it as data). + */ + public String getLowerDPKey() { + return getDataAsString(AREA_CURVE_UNDER); + } + + + /** + * True if the whole area between the two curves shall be filled. + */ + public boolean getPaintBetween() { + String val = getDataAsString(AREA_BETWEEN); + + return val != null && val.equals("true"); + } + + + /** + * Get dataprovider key for the 'upper' curve (we got that information fed + * from the client and store it as data). + */ + public String getUpperDPKey() { + return getDataAsString(AREA_CURVE_OVER); + } + + + /** Return data item that is used to configure name of area. */ + public String getAreaName() { + return getDataAsString(AREA_NAME); + } + + + /** + * Create and return a new AreaCreationState with charting output. + */ + @Override + public State getCurrentState(Object cc) { + final List<Facet> fs = facets.get(getCurrentStateId()); + + AreaCreationState state = new AreaCreationState(); + + StaticState.addDefaultChartOutput(state, "cross_section", fs); + + return state; + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getCurrentState(context)); + + return states; + } + + + /** Trivia. */ + protected State getState(Object context, String stateID) { + return getCurrentState(null); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,163 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.model.minfo.BedHeight; +import de.intevation.flys.artifacts.model.minfo.BedHeightFacet; +import de.intevation.flys.artifacts.model.minfo.BedHeightFactory; +import de.intevation.flys.artifacts.states.StaticState; + +public class BedHeightsArtifact +extends StaticFLYSArtifact +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(BedHeightsArtifact.class); + + private static final String NAME = "bedheights"; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(NAME, FacetActivity.INACTIVE); + } + + public static final String STATIC_STATE_NAME = + "state.additional_bedheights.static"; + + /** Data Item name to know whether we are Heighmarks and reveive + * some data slightly different. */ + public static final String DATA_HEIGHT_TYPE = + "height_marks"; + + /** One and only state to be in. */ + protected transient State state = null; + + + /** + * Trivial Constructor. + */ + public BedHeightsArtifact() { + logger.debug("BedHeightsArtifact.BedHeightsArtifact"); + } + + @Override + public String getName() { + return NAME; + } + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("BedHeightsArtifact.setup"); + + state = new StaticState(STATIC_STATE_NAME); + + if (logger.isDebugEnabled()) { + logger.debug(XMLUtils.toString(data)); + } + + List<Facet> fs = new ArrayList<Facet>(); + String code = getDatacageIDValue(data); + + if (code != null) { + String [] parts = code.split("-"); + + if (parts.length >= 4) { + if (parts[0].equals("bedheight")) { + addStringData("type", parts[1]); + addStringData("height_id", parts[2]); + addStringData("time", parts[3]); + } + int hId = Integer.parseInt(parts[2]); + String bedHName = BedHeightFactory.getHeightName(parts[1], hId); + + Facet bedHFacet = new BedHeightFacet( + "bedheight", + bedHName); + + fs.add(bedHFacet); + facets.put(state.getID(), fs); + } + } + + //spawnState(); + super.setup(identifier, factory, context, callMeta, data); + } + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getState()); + return states; + } + + /** + * Get the "current" state (there is but one). + * @param cc ignored. + * @return the "current" (only possible) state. + */ + @Override + public State getCurrentState(Object cc) { + return getState(); + } + + + /** + * Get the only possible state. + * @return the state. + */ + protected State getState() { + return getState(null, null); + } + + + /** + * Get the state. + * @param context ignored. + * @param stateID ignored. + * @return the state. + */ + @Override + protected State getState(Object context, String stateID) { + return (state != null) + ? state + : new StaticState(STATIC_STATE_NAME); + } + + /** + * Get WKms from factory. + * @param idx param is not needed (TODO?) + * @return WKms according to parameterization (can be null); + */ + public BedHeight getHeight() { + return BedHeightFactory.getHeight( + getDataAsString("type"), + Integer.parseInt(getDataAsString("height_id")), + Integer.parseInt(getDataAsString("time"))); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ChartArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,213 @@ +package de.intevation.flys.artifacts; + +import org.apache.log4j.Logger; + +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.ArtifactNamespaceContext; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifactdatabase.state.Output; + +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.resources.Resources; + + +/** Artifact, open to generate any (?) out. */ +public class ChartArtifact extends FLYSArtifact { + + private static final Logger logger = + Logger.getLogger(ChartArtifact.class); + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callmeta, + Document data) + { + logger.debug("ChartArtifact.setup"); + this.identifier = identifier; + name = "new_chart"; + + List<State> states = getStates(context); + + setCurrentState(states.get(0)); + } + + @Override + protected void appendBackgroundActivity( + ElementCreator cr, + Element root, + CallContext context + ) { + Element inBackground = cr.create("background-processing"); + root.appendChild(inBackground); + + cr.addAttr( + inBackground, + "value", + String.valueOf(context.isInBackground()), + true); + } + + + /** + * Append output mode nodes to a document. + */ + @Override + protected void appendOutputModes( + Document doc, + Element outs, + CallContext context, + String uuid) + { + List<String> stateIds = getPreviousStateIds(); + + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + for (String stateId: stateIds) { + logger.debug("Append output modes for state: " + stateId); + DefaultState state = (DefaultState) engine.getState(stateId); + + List<Output> list = state.getOutputs(); + if (list == null || list.isEmpty()) { + logger.debug("-> No output modes for this state."); + continue; + } + + List<Facet> fs = facets.get(stateId); + + if (fs == null || fs.isEmpty()) { + logger.debug("No facets for previous state found."); + continue; + } + + logger.debug("Found " + fs.size() + " facets in previous states."); + + List<Output> generated = generateOutputs(list, fs); + + ProtocolUtils.appendOutputModes(doc, outs, generated); + } + + try { + DefaultState cur = (DefaultState) getCurrentState(context); + List<Output> list = cur.getOutputs(); + if (list != null && list.size() > 0) { + logger.debug( + "Append output modes for current state: " + cur.getID()); + + List<Facet> fs = facets.get(cur.getID()); + + if (fs != null && fs.size() > 0) { + List<Output> generated = generateOutputs(list, fs); + + logger.debug("Found " + fs.size() + " current facets."); + if (!generated.isEmpty()) { + ProtocolUtils.appendOutputModes( + doc, outs, generated); + } + } + else { + logger.debug("No facets found for the current state."); + } + } + } + catch (IllegalArgumentException iae) { + // state is not valid, so we do not append its outputs. + } + } + + public static class ChartState extends DefaultState { + + public static final String FIELD_MODE = "chart_type"; + + public static final String DURATION_CURVE = + "chart.new.durationcurve"; + + public static final String COMPUTED_DISCHARGE_CURVE = + "chart.new.computeddischargecurve"; + + public static final String DISCHARGE_LONGITUDINAL_CURVE = + "chart.new.longitudinal_section"; + + public static final String W_DIFFERENCES = + "chart.new.w_differences"; + + public static final String WATERLEVEL = + "chart.new.crosssection"; + + public static final String[] CHARTS = { + COMPUTED_DISCHARGE_CURVE, + DURATION_CURVE, + DISCHARGE_LONGITUDINAL_CURVE, + W_DIFFERENCES, + WATERLEVEL }; + + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old) + { + logger.debug("ChartState.computeAdvance"); + + + return null; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] charts = new Element[CHARTS.length]; + + int i = 0; + + for (String chart: CHARTS) { + charts[i++] = createItem( + cr, new String[] { + Resources.getMsg(meta, chart, chart), + chart + }); + } + + return charts; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,105 @@ +package de.intevation.flys.artifacts; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.Hook; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.state.Output; + +import de.intevation.flys.artifacts.datacage.Recommendations; + +public class CollectionMonitor implements Hook { + + public static final String XPATH_RESULT = "/art:result"; + + private static final Logger logger = + Logger.getLogger(CollectionMonitor.class); + + + @Override + public void setup(Node cfg) { + } + + + @Override + public void execute(Artifact artifact, CallContext context, Document doc) { + FLYSArtifact flys = (FLYSArtifact) artifact; + + Element result = (Element) XMLUtils.xpath( + doc, + XPATH_RESULT, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + ElementCreator creator = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element recommended = creator.create("recommended-artifacts"); + result.appendChild(recommended); + + String[] outs = extractOutputNames(flys, context); + Map<String, Object> params = getNoneUserSpecificParameters(flys, context); + + Recommendations rec = Recommendations.getInstance(); + + // TODO For newer official-lines recommendations we actually + // need user-id (null here). + rec.recommend(flys, null, outs, params, recommended); + } + + + /** + * Get outputnames from current state (only the ones for which + * facets exist). + */ + public static String[] extractOutputNames( + FLYSArtifact flys, + CallContext context) + { + if (flys instanceof ChartArtifact) { + return new String[0]; + } + + List<Output> outs = flys.getCurrentOutputs(context); + + int num = outs == null ? 0 : outs.size(); + + String[] names = new String[num]; + + for (int i = 0; i < num; i++) { + names[i] = outs.get(i).getName(); + } + + return names; + } + + + protected Map<String, Object> getNoneUserSpecificParameters( + FLYSArtifact flys, + CallContext context) + { + Map<String, Object> params = new HashMap<String, Object>(1); + params.put("recommended", "true"); + + return params; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,345 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; +import java.util.NavigableMap; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.CrossSectionFacet; +import de.intevation.flys.artifacts.model.FastCrossSectionLineFactory; + +import de.intevation.flys.model.FastCrossSectionLine; + +import de.intevation.flys.model.CrossSection; +import de.intevation.flys.model.CrossSectionLine; +import de.intevation.flys.artifacts.model.CrossSectionFactory; + +import de.intevation.flys.artifacts.states.StaticState; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.services.CrossSectionKMService; + + +/** + * Artifact describing a cross-section. + */ +public class CrossSectionArtifact extends StaticFLYSArtifact { + + /** Name of Artifact. */ + public static final String CS_ARTIFACT_NAME = "cross_section"; + + /** Name of state. */ + public static final String STATIC_STATE_NAME = "state.cross_section"; + + /** Name of data item keeping the position. */ + public static final String DATA_KM = "cross_section.km"; + + /** Name of data item keeping the database id of this c.s.. */ + public static final String DATA_DBID = "cross_section.dbid"; + + /** Name of data item flagging whether we think that we are master. */ + public static final String DATA_IS_MASTER = "cross_section.master?"; + + /** Name of data item flagging whether we are the newest. */ + public static final String DATA_IS_NEWEST = "cross_section.newest?"; + + /** Name of data item storing the previous possible km. */ + public static final String DATA_PREV_KM = "cross_section.km.previous"; + + /** Name of data item storing the next possible km. */ + public static final String DATA_NEXT_KM = "cross_section.km.next"; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(CrossSectionArtifact.class); + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance().register( + CS_ARTIFACT_NAME, + new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String outputName + ) { + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + String data = flys.getDataAsString(DATA_IS_NEWEST); + return data != null && data.equals("1"); + } + return null; + } + }); + } + + /** Return given name. */ + @Override + public String getName() { + return CS_ARTIFACT_NAME; + } + + + /** Store ids, create a CrossSectionFacet. */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.info("CrossSectionArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + + String ids = getDatacageIDValue(data); + + if (ids != null && ids.length() > 0) { + addStringData(DATA_DBID, ids); + logger.debug("CrossSectionArtifacts db-id: " + ids); + } + else { + throw new IllegalArgumentException("No attribute 'ids' found!"); + } + + List<Facet> fs = new ArrayList<Facet>(); + CrossSection cs = CrossSectionFactory.getCrossSection( + Integer.parseInt(ids)); + + List<CrossSectionLine> csls = cs.getLines(); + if (!csls.isEmpty()) { + CrossSectionLine csl = csls.get(0); + // Find min-km of cross sections, + // then set DATA_KM to min(DATA_KM, minCross). + double dataKm = Double.valueOf(getDataAsString(DATA_KM)); + if (dataKm < csl.getKm().doubleValue()) { + addStringData(DATA_KM, csl.getKm().toString()); + } + } + fs.add(new CrossSectionFacet(0, cs.getDescription())); + + // Find out if we are newest and become master if so. + boolean isNewest = CrossSectionFactory.isNewest(cs); + String newString = (isNewest) ? "1" : "0"; + addStringData(DATA_IS_NEWEST, newString); + addStringData(DATA_IS_MASTER, newString); + + StaticState state = (StaticState) getCurrentState(context); + + if (!fs.isEmpty()) { + facets.put(getCurrentStateId(), fs); + } + } + + + /** Copy km where master-artifact "starts". */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + FLYSArtifact winfo = (FLYSArtifact) artifact; + double[] range = FLYSUtils.getKmRange(winfo); + double min = 0.0f; + if (range != null && range.length > 0) { + min = range[0]; + } + this.addStringData(DATA_KM, Double.toString(min)); + } + + + /** Returns next possible km for a cross-section. */ + public Double getNextKm() { + return getDataAsDouble(DATA_NEXT_KM); + } + + + /** Returns previous possible km for a cross-section. */ + public Double getPrevKm() { + return getDataAsDouble(DATA_PREV_KM); + } + + + /** + * Create and return a new StaticState with charting output. + */ + @Override + public State getCurrentState(Object cc) { + final List<Facet> fs = facets.get(getCurrentStateId()); + + StaticState state = new StaticState(STATIC_STATE_NAME) { + @Override + public Object staticCompute(List<Facet> facets) { + if (facets != null) { + facets.addAll(fs); + } + return null; + } + }; + + state.addDefaultChartOutput("cross_section", fs); + + return state; + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getCurrentState(context)); + + return states; + } + + // TODO all data access needs proper caching. + + /** + * Get a DataItem casted to int (0 if fails). + */ + public int getDataAsIntNull(String dataName) { + String val = getDataAsString(dataName); + try { + return Integer.parseInt(val); + } + catch (NumberFormatException e) { + logger.warn("Could not get data " + dataName + " as int", e); + return 0; + } + } + + + /** Returns database-id of cross-section (from data). */ + protected int getDBID() { + return getDataAsIntNull(DATA_DBID); + } + + + /** + * Return position (km) from data, 0 if not found. + */ + protected double getKm() { + String val = getDataAsString(DATA_KM); + try { + return Double.valueOf(val); + } + catch (NumberFormatException e) { + logger.warn("Could not get data " + DATA_KM + " as double", e); + return 0; + } + } + + + /** Returns true if artifact is set to be a "master" (other facets will + * refer to this). */ + public boolean isMaster() { + return !getDataAsString(DATA_IS_MASTER).equals("0"); + } + + + /** + * Get points of Profile of cross section at given kilometer. + * + * @return an array holding coordinates of points of profile ( + * in the form {{x1, x2} {y1, y2}} ). + */ + public double [][] getCrossSectionData() { + logger.info("getCrossSectionData() for cross_section.km " + + getDataAsString(DATA_KM)); + FastCrossSectionLine line = searchCrossSectionLine(); + + return line != null + ? line.fetchCrossSectionProfile() + : null; + } + + + /** + * Get CrossSectionLine spatially closest to what is specified in the data + * "cross_section.km", null if considered too far. + * + * It also adds DataItems to store the next and previous (numerically) + * values at which cross-section data was recorded. + * + * @return CrossSectionLine closest to "cross_section.km", might be null + * if considered too far. + */ + public FastCrossSectionLine searchCrossSectionLine() { + double TOO_FAR = 1d; + CrossSection crossSection = CrossSectionFactory + .getCrossSection(getDBID()); + + if (logger.isDebugEnabled()) { + logger.debug("dbid " + getDBID() + " : " + crossSection); + } + + NavigableMap<Double, Integer> kms = CrossSectionKMService + .getKms(crossSection.getId()); + + Double wishKM = getKm(); + + Double floor = kms.floorKey(wishKM); + Double ceil = kms.ceilingKey(wishKM); + + Double nextKm; + Double prevKm; + + double floorD = floor != null + ? Math.abs(floor - wishKM) + : Double.MAX_VALUE; + + double ceilD = ceil != null + ? Math.abs(ceil - wishKM) + : Double.MAX_VALUE; + + double km; + if (floorD < ceilD) { + km = floor; + } + else { + km = ceil; + } + + // If we are too far from the wished km, return null. + if (Math.abs(km - wishKM) > TOO_FAR) { + return null; + } + + // Store next and previous km. + nextKm = kms.higherKey(km); + prevKm = kms.lowerKey(km); + + if (prevKm == null) { + prevKm = -1d; + } + if (nextKm == null) { + nextKm = -1d; + } + + addStringData(DATA_PREV_KM, prevKm.toString()); + addStringData(DATA_NEXT_KM, nextKm.toString()); + + return FastCrossSectionLineFactory + .getCrossSectionLine(crossSection, km); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,165 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.artifacts.states.WMSBackgroundState; + + +public class ExternalWMSArtifact extends StaticFLYSArtifact { + + public static final String NAME = "external_wms"; + + private static final Logger logger = + Logger.getLogger(ExternalWMSArtifact.class); + + + @Override + public String getName() { + return NAME; + } + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.info("ExternalWMSArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + + String ids = getDatacageIDValue(data); + + if (ids != null && ids.length() > 0) { + addStringData("ids", ids); + } + else { + throw new IllegalArgumentException("No attribute 'ids' found!"); + } + + List<Facet> fs = new ArrayList<Facet>(); + + WMSBackgroundState s = (WMSBackgroundState) getCurrentState(context); + s.computeInit(this, hash(), context, callMeta, fs); + + if (!fs.isEmpty()) { + facets.put(getCurrentStateId(), fs); + } + } + + + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + // do nothing + } + + + @Override + public State getCurrentState(Object cc) { + State s = new ExternalWMSState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getCurrentState(context)); + + return states; + } + + + public static class ExternalWMSState extends WMSBackgroundState { + + protected ExternalWMSArtifact artifact; + + protected String ids; + + + public ExternalWMSState(ExternalWMSArtifact artifact) { + super(); + this.artifact = artifact; + } + + protected String getIds() { + if (ids == null || ids.length() == 0) { + ids = artifact.getDataAsString("ids"); + } + + return ids; + } + + @Override + protected String getFacetType() { + return FLOODMAP_EXTERNAL_WMS; + } + + @Override + protected String getSrid() { + return ""; + } + + @Override + protected String getUrl() { + String ids = getIds(); + String[] parts = ids.split(";"); + + return parts[0]; + } + + @Override + protected String getLayer() { + String ids = getIds(); + String[] parts = ids.split(";"); + + return parts[1]; + } + + @Override + protected String getTitle(CallMeta meta) { + String ids = getIds(); + String[] parts = ids.split(";"); + + return parts[2]; + } + } // end of class ExternalWMSState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1506 @@ +package de.intevation.flys.artifacts; + +import de.intevation.artifactdatabase.ArtifactDatabaseImpl; +import de.intevation.artifactdatabase.DefaultArtifact; +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.data.DefaultStateData; +import de.intevation.artifactdatabase.data.StateData; +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifactdatabase.transition.TransitionEngine; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.Message; +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.artifacts.cache.CacheFactory; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.model.CalculationMessage; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.FLYSUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import javax.xml.xpath.XPathConstants; + +import net.sf.ehcache.Cache; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * The default FLYS artifact with convenience added. + * (Subclass to get fully functional artifacts). + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class FLYSArtifact extends DefaultArtifact { + + /** The logger that is used in this artifact. */ + private static Logger log = Logger.getLogger(FLYSArtifact.class); + + public static final String COMPUTING_CACHE = "computed.values"; + + /** The XPath that points to the input data elements of the FEED document. */ + public static final String XPATH_FEED_INPUT = + "/art:action/art:data/art:input"; + + /** The XPath that points to the name of the target state of ADVANCE. */ + public static final String XPATH_ADVANCE_TARGET = + "/art:action/art:target/@art:name"; + + public static final String XPATH_MODEL_ARTIFACT = + "/art:action/art:template/@uuid"; + + public static final String XPATH_FILTER = + "/art:action/art:filter/art:out"; + + /** The constant string that shows that an operation was successful. */ + public static final String OPERATION_SUCCESSFUL = "SUCCESS"; + + /** The constant string that shows that an operation failed. */ + public static final String OPERATION_FAILED = "FAILURE"; + + /** The identifier of the current state. */ + protected String currentStateId; + + /** The identifiers of previous states on a stack. */ + protected List<String> previousStateIds; + + /** The name of the artifact. */ + protected String name; + + /** The data that have been inserted into this artifact. */ + protected Map<String, StateData> data; + + /** Mapping of state names to created facets. */ + protected Map<String, List<Facet>> facets; + + /** + * Used to generates "view" on the facets (hides facets not matching the + * filter in output of collection); out -> facets. + */ + protected Map<String, List<Facet>> filterFacets; + + + /** + * The default constructor that creates an empty FLYSArtifact. + */ + public FLYSArtifact() { + data = new TreeMap<String, StateData>(); + previousStateIds = new ArrayList<String>(); + facets = new HashMap<String, List<Facet>>(); + } + + /** + * This method appends the static data - that has already been inserted by + * the user - to the static node of the DESCRIBE document. + * + * @param doc The document. + * @param ui The root node. + * @param context The CallContext. + * @param uuid The identifier of the artifact. + */ + protected void appendStaticUI( + Document doc, + Node ui, + CallContext context, + String uuid) + { + List<String> stateIds = getPreviousStateIds(); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + boolean debug = log.isDebugEnabled(); + + for (String stateId: stateIds) { + if (debug) { + log.debug("Append static data for state: " + stateId); + } + DefaultState state = (DefaultState) engine.getState(stateId); + + ui.appendChild(state.describeStatic(this, doc, ui, context, uuid)); + } + } + + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + public String getName() { + return name; + } + + + /** + * Initialize the artifact and insert new data if <code>data</code> contains + * information necessary for this artifact. + * + * @param identifier The UUID. + * @param factory The factory that is used to create this artifact. + * @param context The CallContext. + * @param data Some optional data. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("Setup this artifact with the uuid: " + identifier); + } + + super.setup(identifier, factory, context, callMeta, data); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + + List<State> states = getStates(context); + + String name = getName(); + + if (debug) { + log.debug("Set initial state for artifact '" + name + "'"); + } + + if (states == null) { + log.error("No states found from which an initial " + + "state could be picked."); + } + setCurrentState(states.get(0)); + + String model = XMLUtils.xpathString( + data, + XPATH_MODEL_ARTIFACT, + ArtifactNamespaceContext.INSTANCE); + + if (model != null && model.length() > 0) { + ArtifactDatabase db = (ArtifactDatabase) flysContext.get( + ArtifactDatabaseImpl.GLOBAL_CONTEXT_KEY); + + try { + initialize(db.getRawArtifact(model), context, callMeta); + } + catch (ArtifactDatabaseException adbe) { + log.error(adbe, adbe); + } + } + + filterFacets = buildFilterFacets(data); + } + + + /** Get copy of previous state ids as Strings in list. */ + protected List<String> clonePreviousStateIds() { + return new ArrayList<String>(previousStateIds); + } + + + /** + * Copies data item from other artifact to this artifact. + * + * @param other Artifact from which to get data. + * @param name Name of data. + */ + protected void importData(FLYSArtifact other, final String name) { + if (other == null) { + log.error("No other art. to import data " + name + " from."); + return; + } + + StateData sd = other.getData(name); + + if (sd == null) { + log.warn("Other artifact has no data " + name + "."); + return; + } + + this.addData(name, sd); + } + + + protected Map<String, StateData> cloneData() { + Map<String, StateData> copy = new TreeMap<String, StateData>(); + + for (Map.Entry<String, StateData> entry: data.entrySet()) { + copy.put(entry.getKey(), entry.getValue().deepCopy()); + } + + return copy; + } + + /** + * Return a copy of the facet mapping. + * @return Mapping of state-ids to facets. + */ + protected Map<String, List<Facet>> cloneFacets() { + Map<String, List<Facet>> copy = new HashMap<String, List<Facet>>(); + + for (Map.Entry<String, List<Facet>> entry: facets.entrySet()) { + List<Facet> facets = entry.getValue(); + List<Facet> facetCopies = new ArrayList<Facet>(facets.size()); + for (Facet facet: facets) { + facetCopies.add(facet.deepCopy()); + } + copy.put(entry.getKey(), facetCopies); + } + + return copy; + } + + + /** + * (called from setup). + * @param artifact master-artifact (if any, otherwise initialize is not called). + */ + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + if (!(artifact instanceof FLYSArtifact)) { + return; + } + + FLYSArtifact flys = (FLYSArtifact)artifact; + + currentStateId = flys.currentStateId; + previousStateIds = flys.clonePreviousStateIds(); + name = flys.name; + data = flys.cloneData(); + facets = flys.cloneFacets(); + // Do not clone filter facets! + + ArrayList<String> stateIds = (ArrayList<String>) getPreviousStateIds(); + ArrayList<String> toInitialize = (ArrayList<String>) stateIds.clone(); + + toInitialize.add(getCurrentStateId()); + + for (String stateId: toInitialize) { + State state = getState(context, stateId); + + if (state != null) { + state.initialize(artifact, this, context, callMeta); + } + } + } + + + /** + * Builds filter facets from document. + * @see filterFacets + */ + protected Map<String, List<Facet>> buildFilterFacets(Document document) { + + NodeList nodes = (NodeList)XMLUtils.xpath( + document, + XPATH_FILTER, + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + if (nodes == null || nodes.getLength() == 0) { + return null; + } + + Map<String, List<Facet>> result = new HashMap<String, List<Facet>>(); + + for (int i = 0, N = nodes.getLength(); i < N; ++i) { + Element element = (Element)nodes.item(i); + String oName = element.getAttribute("name"); + if (oName.length() == 0) { + continue; + } + + List<Facet> facets = new ArrayList<Facet>(); + + NodeList facetNodes = element.getElementsByTagNameNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "facet"); + + for (int j = 0, M = facetNodes.getLength(); j < M; ++j) { + Element facetElement = (Element)facetNodes.item(j); + + String fName = facetElement.getAttribute("name"); + + int index; + try { + index = Integer.parseInt(facetElement.getAttribute("index")); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + index = 0; + } + facets.add(new DefaultFacet(index, fName, "")); + } + + if (!facets.isEmpty()) { + result.put(oName, facets); + } + } + + return result; + } + + + /** + * Insert new data included in <code>input</code> into the current state. + * + * @param target XML document that contains new data. + * @param context The CallContext. + * + * @return a document that contains a SUCCESS or FAILURE message. + */ + @Override + public Document feed(Document target, CallContext context) { + log.debug("FLYSArtifact.feed()"); + + Document doc = XMLUtils.newDocument(); + + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element result = creator.create("result"); + doc.appendChild(result); + + try { + saveData(target, context); + + compute(context, ComputeType.FEED, true); + + return describe(target, context); + } + catch (IllegalArgumentException iae) { + // do not store state if validation fails. + context.afterCall(CallContext.NOTHING); + creator.addAttr(result, "type", OPERATION_FAILED, true); + + result.setTextContent(iae.getMessage()); + } + + return doc; + } + + /** + * This method returns a description of this artifact. + * + * @param data Some data. + * @param context The CallContext. + * + * @return the description of this artifact. + */ + @Override + public Document describe(Document data, CallContext context) { + + if (log.isDebugEnabled()) { + log.debug( + "Describe: the current state is: " + getCurrentStateId()); + dumpArtifact(); + } + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + + StateEngine stateEngine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + TransitionEngine transitionEngine = (TransitionEngine) flysContext.get( + FLYSContext.TRANSITION_ENGINE_KEY); + + List<State> reachable = transitionEngine.getReachableStates( + this, getCurrentState(context), stateEngine); + + Document description = XMLUtils.newDocument(); + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + description, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = ProtocolUtils.createRootNode(creator); + description.appendChild(root); + + State current = getCurrentState(context); + + ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash()); + ProtocolUtils.appendState(creator, root, current); + ProtocolUtils.appendReachableStates(creator, root, reachable); + + appendBackgroundActivity(creator, root, context); + + Element ui = ProtocolUtils.createArtNode( + creator, "ui", null, null); + + Element staticUI = ProtocolUtils.createArtNode( + creator, "static", null, null); + + Element outs = ProtocolUtils.createArtNode( + creator, "outputmodes", null, null); + appendOutputModes(description, outs, context, identifier()); + + appendStaticUI(description, staticUI, context, identifier()); + + Element name = ProtocolUtils.createArtNode( + creator, "name", + new String[] { "value" }, + new String[] { getName() }); + + Element dynamic = current.describe( + this, + description, + root, + context, + identifier()); + + if (dynamic != null) { + ui.appendChild(dynamic); + } + + ui.appendChild(staticUI); + + root.appendChild(name); + root.appendChild(ui); + root.appendChild(outs); + + return description; + } + + /** Override me! */ + + protected void appendBackgroundActivity( + ElementCreator cr, + Element root, + CallContext context + ) { + LinkedList<Message> messages = context.getBackgroundMessages(); + + if (messages == null) { + return; + } + + Element inBackground = cr.create("background-processing"); + root.appendChild(inBackground); + + cr.addAttr( + inBackground, + "value", + String.valueOf(context.isInBackground()), + true); + + CalculationMessage message = (CalculationMessage) messages.getLast(); + cr.addAttr( + inBackground, + "steps", + String.valueOf(message.getSteps()), + true); + + cr.addAttr( + inBackground, + "currentStep", + String.valueOf(message.getCurrentStep()), + true); + + inBackground.setTextContent(message.getMessage()); + } + + /** + * Append output mode nodes to a document. + */ + protected void appendOutputModes( + Document doc, + Element outs, + CallContext context, + String uuid) + { + List<Output> generated = getOutputs(context); + + if (log.isDebugEnabled()) { + log.debug("This Artifact has " + generated.size() + " Outputs."); + } + + ProtocolUtils.appendOutputModes(doc, outs, generated); + } + + + /** + * This method handles request for changing the current state of an + * artifact. It is possible to step forward or backward. + * + * @param target The incoming ADVANCE document. + * @param context The CallContext. + * + * @return a document that contains a SUCCESS or FAILURE message. + */ + @Override + public Document advance(Document target, CallContext context) { + + boolean debug = log.isDebugEnabled(); + + Document doc = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element result = ec.create("result"); + + String currentStateId = getCurrentStateId(); + String targetState = XMLUtils.xpathString( + target, XPATH_ADVANCE_TARGET, ArtifactNamespaceContext.INSTANCE); + + if (debug) { + log.debug("FLYSArtifact.advance() to '" + targetState + "'"); + } + + if (!currentStateId.equals(targetState) + && isStateReachable(targetState, context)) + { + if (debug) { + log.debug("Advance: Step forward"); + } + + List<String> prev = getPreviousStateIds(); + prev.add(currentStateId); + + setCurrentStateId(targetState); + + if (debug) { + log.debug("Compute data for state: " + targetState); + } + compute(context, ComputeType.ADVANCE, true); + + return describe(target, context); + } + else if (isPreviousState(targetState, context)) { + if (debug) { + log.debug("Advance: Step back to"); + } + + List<String> prevs = getPreviousStateIds(); + int targetIdx = prevs.indexOf(targetState); + int start = prevs.size() - 1; + + destroyStates(prevs, context); + + for (int i = start; i >= targetIdx; i--) { + String prev = prevs.get(i); + if (debug) { + log.debug("Remove state id '" + prev + "'"); + } + + prevs.remove(prev); + facets.remove(prev); + } + + destroyState(getCurrentStateId(), context); + setCurrentStateId(targetState); + + return describe(target, context); + } + + log.warn("Advance: Cannot advance to '" + targetState + "'"); + ec.addAttr(result, "type", OPERATION_FAILED, true); + + doc.appendChild(result); + + return doc; + } + + + /** + * Returns the identifier of the current state. + * + * @return the identifier of the current state. + */ + public String getCurrentStateId() { + return currentStateId; + } + + + /** + * Sets the identifier of the current state. + * + * @param id the identifier of a state. + */ + protected void setCurrentStateId(String id) { + currentStateId = id; + } + + + /** + * Set the current state of this artifact. <b>NOTE</b>We don't store the + * State object itself - which is not necessary - but its identifier. So + * this method will just call the setCurrentStateId() method with the + * identifier of <i>state</i>. + * + * @param state The new current state. + */ + protected void setCurrentState(State state) { + setCurrentStateId(state.getID()); + } + + + /** + * Returns the current state of the artifact. + * + * @return the current State of the artifact. + */ + public State getCurrentState(Object context) { + return getState(context, getCurrentStateId()); + } + + + /** + * Get list of existant states for this Artifact. + * @param context Contex to get StateEngine from. + * @return list of states. + */ + protected List<State> getStates(Object context) { + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + return engine.getStates(getName()); + } + + + /** + * Get state with given ID. + * @param context Context to get StateEngine from. + * @param stateID ID of state to get. + * @return state with given ID. + */ + protected State getState(Object context, String stateID) { + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + return engine.getState(stateID); + } + + + /** + * Returns the vector of previous state identifiers. + * + * @return the vector of previous state identifiers. + */ + protected List<String> getPreviousStateIds() { + return previousStateIds; + } + + + /** + * Get all previous and the current state id. + * @return #getPreviousStateIds() + #getCurrentStateId() + */ + public List<String> getStateHistoryIds() { + ArrayList<String> prevIds = (ArrayList) getPreviousStateIds(); + ArrayList<String> allIds = (ArrayList) prevIds.clone(); + + allIds.add(getCurrentStateId()); + return allIds; + } + + + /** + * Adds a new StateData item to the data pool of this artifact. + * + * @param name the name of the data object. + * @param data the data object itself. + */ + protected void addData(String name, StateData data) { + this.data.put(name, data); + } + + + protected StateData removeData(String name) { + return this.data.remove(name); + } + + + /** + * This method returns a specific StateData object that is stored in the + * data pool of this artifact. + * + * @param name The name of the data object. + * + * @return the StateData object if existing, otherwise null. + */ + public StateData getData(String name) { + return data.get(name); + } + + + /** Return named data item, null if not found. */ + public String getDataAsString(String name) { + StateData data = getData(name); + return data != null ? (String) data.getValue() : null; + } + + + /** + * This method returns the value of a StateData object stored in the data + * pool of this Artifact as Integer. + * + * @param name The name of the StateData object. + * + * @return an Integer representing the value of the data object or null if + * no object was found for <i>name</i>. + * + * @throws NumberFormatException if the value of the data object could not + * be transformed into an Integer. + */ + public Integer getDataAsInteger(String name) + throws NumberFormatException + { + String value = getDataAsString(name); + + if (value != null && value.length() > 0) { + return Integer.parseInt(value); + } + + return null; + } + + + /** + * This method returns the value of a StateData object stored in the data + * pool of this Artifact as Double. + * + * @param name The name of the StateData object. + * + * @return an Double representing the value of the data object or null if + * no object was found for <i>name</i>. + * + * @throws NumberFormatException if the value of the data object could not + * be transformed into a Double. + */ + public Double getDataAsDouble(String name) + throws NumberFormatException + { + String value = getDataAsString(name); + + if (value != null && value.length() > 0) { + return Double.parseDouble(value); + } + + return null; + } + + + /** + * This method returns the value of a StateData object stored in the data + * pool of this Artifact as Long. + * + * @param name The name of the StateData object. + * + * @return a Long representing the value of the data object or null if + * no object was found for <i>name</i>. + * + * @throws NumberFormatException if the value of the data object could not + * be transformed into a Long. + */ + public Long getDataAsLong(String name) + throws NumberFormatException + { + String value = getDataAsString(name); + + if (value != null && value.length() > 0) { + return Long.parseLong(value); + } + + return null; + } + + + /** + * This method returns the value of a StateData object stored in the data + * pool of this Artifact is Boolean using Boolean.valueOf(). + * + * @param name The name of the StateData object. + * + * @return a Boolean representing the value of the data object or null if no + * such object is existing. + */ + public Boolean getDataAsBoolean(String name) { + String value = getDataAsString(name); + + if (value == null || value.length() == 0) { + return null; + } + + return Boolean.valueOf(value); + } + + + /** + * Add StateData containing a given string. + * @param name Name of the data object. + * @param value String to store. + */ + public void addStringData(String name, String value) { + addData(name, new DefaultStateData(name, null, null, value)); + } + + + public Collection<StateData> getAllData() { + return data.values(); + } + + + public List<Facet> getFacets() { + List<Facet> all = new ArrayList<Facet>(); + + for (List<Facet> fs: facets.values()) { + all.addAll(fs); + } + + return all; + } + + + /** + * Get facet as stored internally, with equalling name and index than given + * facet. + * @param facet that defines index and name of facet searched. + * @return facet instance or null if not found. + */ + public Facet getNativeFacet(Facet facet) { + String name = facet.getName(); + int index = facet.getIndex(); + + for (List<Facet> fs: facets.values()) { + for (Facet f: fs) { + if (f.getIndex() == index && f.getName().equals(name)) { + return f; + } + } + } + + log.warn("Could not find facet: " + name + " at " + index); + return null; + } + + + /** + * This method stores the data that is contained in the FEED document. + * + * @param feed The FEED document. + * @param xpath The XPath that points to the data nodes. + */ + public void saveData(Document feed, CallContext context) + throws IllegalArgumentException + { + if (feed == null) { + throw new IllegalArgumentException("error_feed_no_data"); + } + + NodeList nodes = (NodeList) XMLUtils.xpath( + feed, + XPATH_FEED_INPUT, + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + if (nodes == null || nodes.getLength() == 0) { + throw new IllegalArgumentException("error_feed_no_data"); + } + + boolean debug = log.isDebugEnabled(); + + int count = nodes.getLength(); + + if (debug) { + log.debug("Try to save " + count + " data items."); + } + + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + DefaultState current = (DefaultState) getCurrentState(context); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + for (int i = 0; i < count; i++) { + Element node = (Element)nodes.item(i); + + String name = node.getAttributeNS(uri, "name"); + String value = node.getAttributeNS(uri, "value"); + + if (name.length() > 0 && value.length() > 0) { + if (debug) { + log.debug("Save data item for '" + name + "' : " + value); + } + + StateData model = engine.getStateData(getName(), name); + + StateData sd = model != null + ? model.deepCopy() + : new DefaultStateData(name, null, null, value); + + addData( + name, current.transform(this, context, sd, name, value)); + } + else if (name.length() > 0 && value.length() == 0) { + if (removeData(name) != null && debug) { + log.debug("Removed data '" + name + "' successfully."); + } + } + } + + current.validate(this); + } + + + /** + * Determines if the state with the identifier <i>stateId</i> is reachable + * from the current state. The determination itself takes place in the + * TransitionEngine. + * + * @param stateId The identifier of a state. + * @param context The context object. + * + * @return true, if the state specified by <i>stateId</i> is reacahble, + * otherwise false. + */ + protected boolean isStateReachable(String stateId, Object context) { + + if (log.isDebugEnabled()) { + log.debug("Determine if the state '" + stateId + "' is reachable."); + } + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + + State currentState = getCurrentState(context); + StateEngine sEngine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + TransitionEngine tEngine = (TransitionEngine) flysContext.get( + FLYSContext.TRANSITION_ENGINE_KEY); + + return tEngine.isStateReachable(this, stateId, currentState, sEngine); + } + + + /** + * Determines if the state with the identifier <i>stateId</i> is a previous + * state of the current state. + * + * @param stateId The target state identifier. + * @param context The context object. + */ + protected boolean isPreviousState(String stateId, Object context) { + if (log.isDebugEnabled()) { + log.debug("Determine if the state '" + stateId + "' is old."); + } + + return getPreviousStateIds().contains(stateId); + } + + + /** + * Computes the hash code of the entered values. + * + * @return a hash code. + */ + @Override + public String hash() { + Set<Map.Entry<String, StateData>> entries = data.entrySet(); + + long hash = 0L; + int shift = 3; + + for (Map.Entry<String, StateData> entry: entries) { + String key = entry.getKey(); + Object value = entry.getValue().getValue(); + + hash ^= ((long)key.hashCode() << shift) + | ((long)value.hashCode() << (shift + 3)); + shift += 2; + } + + return getCurrentStateId() + hash; + } + + + /** + * Return List of outputs, where combinations of outputname and filtername + * that match content in filterFacets is left out. + * @return filtered Outputlist. + */ + protected List<Output> filterOutputs(List<Output> outs) { + if (filterFacets == null || filterFacets.isEmpty()) { + log.debug("No filter for Outputs."); + return outs; + } + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Filter Facets with " + filterFacets.size() + " filters."); + } + + List<Output> filtered = new ArrayList<Output>(); + + for (Output out: outs) { + String outName = out.getName(); + + if (debug) { + log.debug(" filter Facets for Output: " + outName); + } + + List<Facet> fFacets = filterFacets.get(outName); + if (fFacets != null) { + if (debug) { + log.debug("" + fFacets.size() + " filters for: " + outName); + for (Facet tmp: fFacets) { + log.debug(" filter = '" + tmp.getName() + "'"); + } + } + + List<Facet> resultFacets = new ArrayList<Facet>(); + + for (Facet facet: out.getFacets()) { + for (Facet fFacet: fFacets) { + if (facet.getIndex() == fFacet.getIndex() + && facet.getName().equals(fFacet.getName())) { + resultFacets.add(facet); + break; + } + } + } + + if (debug) { + log.debug( + "Facets after filtering = " + resultFacets.size()); + } + + if (!resultFacets.isEmpty()) { + DefaultOutput nout = new DefaultOutput( + out.getName(), + out.getDescription(), + out.getMimeType(), + resultFacets); + filtered.add(nout); + } + } + } + + if (debug) { + log.debug("All Facets after filtering = " + filtered.size()); + } + + return filtered; + } + + + /** + * Get all outputs that the Artifact can do in this state (which includes + * all previous states). + * + * @return list of outputs + */ + public List<Output> getOutputs(Object context) { + if (log.isDebugEnabled()) { + log.debug("##### Get Outputs for: " + identifier() + " #####"); + dumpArtifact(); + } + + List<String> stateIds = getPreviousStateIds(); + List<Output> generated = new ArrayList<Output>(); + + for (String stateId: stateIds) { + DefaultState state = (DefaultState) getState(context, stateId); + generated.addAll(getOutputForState(state)); + } + + generated.addAll(getCurrentOutputs(context)); + + return filterOutputs(generated); + } + + + /** + * Get output(s) for current state. + * @return list of outputs for current state. + */ + public List<Output> getCurrentOutputs(Object context) { + DefaultState cur = (DefaultState) getCurrentState(context); + + try { + if (cur.validate(this)) { + return getOutputForState(cur); + } + } + catch (IllegalArgumentException iae) { } + + return new ArrayList<Output>(); + } + + + /** + * Get output(s) for a specific state. + * @param state State of interest + * @return list of output(s) for given state. + */ + protected List<Output> getOutputForState(DefaultState state) { + + if (state == null) { + log.error("state == null: This should not happen!"); + return new ArrayList<Output>(); + } + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("Find Outputs for State: " + state.getID()); + } + + List<Output> list = state.getOutputs(); + if (list == null || list.isEmpty()) { + if (debug) { + log.debug("-> No output modes for this state."); + } + return new ArrayList<Output>(); + } + + String stateId = state.getID(); + + List<Facet> fs = facets.get(stateId); + + if (fs == null || fs.isEmpty()) { + if (debug) { + log.debug("No facets found."); + } + return new ArrayList<Output>(); + } + + List<Output> gen = generateOutputs(list, fs); + + if (debug) { + log.debug("State '" + stateId + "' has " + gen.size() + " outs"); + } + + return gen; + } + + + /** + * Generate a list of outputs with facets from fs if type is found in list + * of output. + * + * @param list List of outputs + * @param fs List of facets + */ + protected List<Output> generateOutputs(List<Output> list, List<Facet> fs) { + List<Output> generated = new ArrayList<Output>(); + + boolean debug = log.isDebugEnabled(); + + for (Output out: list) { + Output o = new DefaultOutput( + out.getName(), + out.getDescription(), + out.getMimeType(), + out.getType()); + + Set<String> outTypes = new HashSet<String>(); + + for (Facet f: out.getFacets()) { + if (outTypes.add(f.getName()) && debug) { + log.debug("configured facet " + f); + } + } + + boolean facetAdded = false; + for (Facet f: fs) { + String type = f.getName(); + + if (outTypes.contains(type)) { + if (debug) { + log.debug("Add facet " + f); + } + facetAdded = true; + o.addFacet(f); + } + } + + if (facetAdded) { + generated.add(o); + } + } + + return generated; + } + + + /** + * Dispatches the computation request to compute(CallContext context, String + * hash) with the current hash value of the artifact which is provided by + * hash(). + * + * @param context The CallContext. + */ + public Object compute( + CallContext context, + ComputeType type, + boolean generateFacets + ) { + return compute(context, hash(), type, generateFacets); + } + + + /** + * Dispatches computation requests to the current state which needs to + * implement a createComputeCallback(String hash, FLYSArtifact artifact) + * method. + * + * @param context The CallContext. + * @param hash The hash value which is used to fetch computed data from + * cache. + * + * @return the computed data. + */ + public Object compute( + CallContext context, + String hash, + ComputeType type, + boolean generateFacets + ) { + DefaultState current = (DefaultState) getCurrentState(context); + return compute(context, hash, current, type, generateFacets); + } + + + /** + * Like compute, but identify State by it id (string). + */ + public Object compute( + CallContext context, + String hash, + String stateID, + ComputeType type, + boolean generateFacets + ) { + DefaultState current = + (stateID == null) + ? (DefaultState)getCurrentState(context) + : (DefaultState)getState(context, stateID); + + if (hash == null) { + hash = hash(); + } + + return compute(context, hash, current, type, generateFacets); + } + + + /** + * Let current state compute and register facets. + * + * @param key key of state + * @param state state + * @param type Type of compute + * @param generateFacets Whether new facets shall be generated. + */ + public Object compute( + CallContext context, + String key, + DefaultState state, + ComputeType type, + boolean generateFacets + ) { + String stateID = state.getID(); + + List<Facet> fs = (generateFacets) ? new ArrayList<Facet>() : null; + + try { + Cache cache = CacheFactory.getCache(COMPUTING_CACHE); + + Object old = null; + + if (cache != null) { + net.sf.ehcache.Element element = cache.get(key); + if (element != null) { + log.debug("Got computation result from cache."); + old = element.getValue(); + } + } + else { + log.debug("cache not configured."); + } + + Object res; + switch (type) { + case FEED: + res = state.computeFeed(this, key, context, fs, old); + break; + case ADVANCE: + res = state.computeAdvance(this, key, context, fs, old); + break; + case INIT: + res = state.computeInit(this, key, context, context.getMeta(), fs); + default: + res = null; + } + + if (cache != null && old != res && res != null) { + log.debug("Store computation result to cache."); + net.sf.ehcache.Element element = + new net.sf.ehcache.Element(key, res); + cache.put(element); + } + + return res; + } + finally { + if (generateFacets) { + if (fs.isEmpty()) { + facets.remove(stateID); + } + else { + facets.put(stateID, fs); + } + } + } + } + + + /** + * Method to dump the artifacts state/data. + */ + protected void dumpArtifact() { + log.debug("++++++++++++++ DUMP ARTIFACT DATA +++++++++++++++++"); + // Include uuid, type, name + + log.debug("------ DUMP DATA ------"); + Collection<StateData> allData = data.values(); + + for (StateData d: allData) { + String name = d.getName(); + String value = (String) d.getValue(); + + log.debug("- " + name + ": " + value); + } + + log.debug("------ DUMP PREVIOUS STATES ------"); + List<String> stateIds = getPreviousStateIds(); + + for (String id: stateIds) { + log.debug("- State: " + id); + } + + log.debug("CURRENT STATE: " + getCurrentStateId()); + + debugFacets(); + dumpFilterFacets(); + + log.debug("++++++++++++++ END ARTIFACT DUMP +++++++++++++++++"); + } + + + protected void debugFacets() { + log.debug("######### FACETS #########"); + Set<Map.Entry<String, List<Facet>>> entries = facets.entrySet(); + + for (Map.Entry<String, List<Facet>> entry: entries) { + String out = entry.getKey(); + List<Facet> fs = entry.getValue(); + for (Facet f: fs) { + log.debug(" # " + out + " : " + f.getName()); + } + } + + log.debug("######## FACETS END ########"); + } + + + protected void dumpFilterFacets() { + log.debug("######## FILTER FACETS ########"); + + if (filterFacets == null || filterFacets.isEmpty()) { + log.debug("No Filter Facets defined."); + return; + } + + Set<Map.Entry<String, List<Facet>>> entries = filterFacets.entrySet(); + for (Map.Entry<String, List<Facet>> entry: entries) { + String out = entry.getKey(); + List<Facet> filters = entry.getValue(); + + log.debug("There are " + filters.size() + " filters for: " +out); + + for (Facet filter: filters) { + log.debug(" filter: " + filter.getName()); + } + } + + log.debug("######## FILTER FACETS END ########"); + } + + + protected void destroyState(String id, Object context) { + State s = getState(context, id); + s.endOfLife(this, context); + } + + + /** + * Calls endOfLife() for each state in the list <i>ids</i>. + * + * @param ids The State IDs that should be destroyed. + * @param context The FLYSContext. + */ + protected void destroyStates(List<String> ids, Object context) { + for (int i = 0, num = ids.size(); i < num; i++) { + destroyState(ids.get(i), context); + } + } + + + /** + * Destroy the states. + */ + @Override + public void endOfLife(Object context) { + if (log.isDebugEnabled()) { + log.debug("FLYSArtifact.endOfLife: " + identifier()); + } + + ArrayList<String> ids = (ArrayList<String>) getPreviousStateIds(); + ArrayList<String> toDestroy = (ArrayList<String>) ids.clone(); + + toDestroy.add(getCurrentStateId()); + + destroyStates(toDestroy, context); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FixationArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,35 @@ +package de.intevation.flys.artifacts; + +import org.apache.log4j.Logger; + +/** + * The default fixation analysis artifact. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixationArtifact +extends FLYSArtifact +{ + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(FixationArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "fixanalysis"; + + /** + * The default constructor. + */ + public FixationArtifact() { + } + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + @Override + public String getName() { + return ARTIFACT_NAME; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,187 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.flys.artifacts.states.DefaultState; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.model.DischargeTables; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * Artifact to get discharge curves at gauges. + */ +public class GaugeDischargeArtifact +extends WINFOArtifact +implements FacetTypes +{ + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(GaugeDischargeArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "gaugedischarge"; + + + /** + * Trivial Constructor. + */ + public GaugeDischargeArtifact() { + logger.debug("GaugeDischargeArtifact.GaugeDischargeArtifact()"); + } + + + /** + * Gets called from factory, to set things up. + * Especially, when loaded via datacage mechanisms, provide the + * data document. + * @param data filled with stuff from dc, if any. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("GaugeDischargeArtifact.setup"); + String ids = StaticFLYSArtifact.getDatacageIDValue(data); + addStringData("ids", ids); + logger.debug("id for gaugedischarge: " + ids); + super.setup(identifier, factory, context, callMeta, data); + } + + + /** Return the name of this artifact. */ + public String getName() { + return ARTIFACT_NAME; + } + + + /** + * Setup state and facet, copy from master artifact. + */ + @Override + protected void initialize(Artifact art, Object context, CallMeta meta) { + logger.debug("GaugeDischargeArtifact.initialize"); + List<Facet> fs = new ArrayList<Facet>(); + FLYSArtifact artifact = (FLYSArtifact) art; + importData(artifact, "river"); + + // Get the location(s) + //importData(artifact, "ld_mode", ld_from, ld_to, ld_locations + addStringData("ld_from", "0"); + addStringData("ld_to", "1000"); + addStringData("ld_mode", "distance"); + + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in GaugeDischargeArtifact.initialize. (" + + state.getID() + "/ " + getCurrentStateId() + ")."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in GaugeDischargeArtifact.initialize (" + + state.getID() + "/ "+getCurrentStateId()+")."); + } + } + + + /** Get the Gauges name which came with datacage data-document. */ + public String getGaugeName() { + return this.getDataAsString("ids"); + } + + + /** Get the Gauges which came with datacage data-document. */ + public Gauge getGauge() { + River river = FLYSUtils.getRiver(this); + return river.determineGaugeByName(getGaugeName()); + } + + + /** + * Returns the data that is used to create discharge curves. + * @return CalculationResult with WQKms. + */ + public CalculationResult getDischargeCurveData() { + + River river = FLYSUtils.getRiver(this); + if (river == null) { + return error(new WQKms[0], "no.river.selected"); + } + /* + // This one would allow to automatically pick the right Gauge. + double [] distance = FLYSUtils.getKmRange(this); + logger.debug("getDischargeCurveData: get range"); + + if (distance == null) { + return error(new WQKms[0], "no.range.found"); + } + + List<Gauge> gauges = river.determineGauges(distance[0], distance[1]); + logger.debug("getDischargeCurveData: got " + gauges.size() + " gauges"); + + if (gauges.isEmpty()) { + return error(new WQKms[0], "no.gauge.selected"); + } + + String [] names = new String[gauges.size()]; + + for (int i = 0; i < names.length; ++i) { + names[i] = gauges.get(i).getName(); + logger.debug("getDischargeCurveData: name " + names[i]); + } + */ + + DischargeTables dt = new DischargeTables(river.getName(), getDataAsString("ids")); + + Map<String, double [][]> map = dt.getValues(100); + + ArrayList<WQKms> res = new ArrayList<WQKms>(); + + Gauge gauge = river.determineGaugeByName(this.getDataAsString("ids")); + + String name = getGaugeName(); + double [][] values = map.get(name); + if (values == null) { + logger.error("No values for this gauge / discharge found."); + return error(new WQKms[0], "no.gauge.found"); + } + for (int i = 0 ; i < values[0].length; i++) { + values[0][i] += gauge.getDatum().doubleValue(); + } + double [] kms = new double[values[0].length]; + Arrays.fill(kms, gauge.getStation().doubleValue()); + res.add(new WQKms(kms, values[0], values[1], name)); + + return new CalculationResult( + res.toArray(new WQKms[res.size()]), + new Calculation()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/HYKArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,125 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + + +import de.intevation.flys.artifacts.states.DefaultState; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; + + +/** + * Artifact to get hydr zones (HYKs). + */ +public class HYKArtifact extends StaticFLYSArtifact { + + /** Name of Artifact. */ + public static final String HYK_ARTIFACT_NAME = "hyk"; + + /** Name of data item keeping the hyk id to load formations from. */ + public static final String HYK_ID = "hyk_artifact.data.id"; + + /** Name of data item keeping the km of cs master. */ + public static final String HYK_KM = "hyk_artifact.data.km"; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(HYKArtifact.class); + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(HYK_ARTIFACT_NAME, FacetActivity.INACTIVE); + } + + /** Return given name. */ + @Override + public String getName() { + return HYK_ARTIFACT_NAME; + } + + + /** Store ids, do super.setup. */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.info("HYKArtifact.setup"); + + String ids = getDatacageIDValue(data); + + logger.info("HYKArtifact.setup: id is " + ids); + + addStringData(HYK_ID, ids); + + super.setup(identifier, factory, context, callMeta, data); + } + + + /** Set km as Data. */ + public void setKm(double km) { + addStringData(HYK_KM, Double.toString(km)); + } + + + /** Get km from state data. */ + public double getKm() { + Double km = getDataAsDouble(HYK_KM); + if (km == null) { + // XXX returning 0 is to be compatible to older versions that had an + // own method getDataAsDouble that returned 0 if parsing the + // parameter failed. + return 0; + } + else { + return km; + } + } + + + /** Get hyk-id from state data. */ + public int getHykId() { + return getDataAsInteger(HYK_ID); + } + + + /** Do not copy data from daddyfact. */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + logger.debug("HYKArtifact.initialize"); + WINFOArtifact winfo = (WINFOArtifact) artifact; + importData(winfo, "river"); + + List<Facet> fs = new ArrayList<Facet>(); + + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, callMeta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in HYKArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in HYKArtifact.initialize (" + + state.getID() + ")."); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,31 @@ +package de.intevation.flys.artifacts; + +/** + * The default MINFO artifact. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MINFOArtifact +extends FLYSArtifact +{ + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "minfo"; + + + /** + * The default constructor. + */ + public MINFOArtifact() { + } + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + @Override + public String getName() { + return ARTIFACT_NAME; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,337 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.data.DefaultStateData; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.MainValue; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.MainValuesQFacet; +import de.intevation.flys.artifacts.model.MainValuesWFacet; +import de.intevation.flys.artifacts.model.NamedDouble; +import de.intevation.flys.artifacts.model.WstValueTable; +import de.intevation.flys.artifacts.model.WstValueTableFactory; + +import de.intevation.flys.artifacts.states.StaticState; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * Artifact to access names of Points Of Interest along a segment of a river. + * This artifact neglects (Static)FLYSArtifacts capabilities of interaction + * with the StateEngine by overriding the getState*-methods. + */ +public class MainValuesArtifact +extends StaticFLYSArtifact +implements FacetTypes +{ + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(MainValuesArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "mainvalue"; + + /** The name of the static state for this artifact. */ + public static final String STATIC_STATE_NAME = "state.mainvalue.static"; + + /** One and only state to be in. */ + protected transient State state = null; + + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance().register( + ARTIFACT_NAME, + new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String outputName + ) { + return outputName.equals("computed_discharge_curve") + || outputName.equals("duration_curve"); + } + }); + } + + /** + * Trivial Constructor. + */ + public MainValuesArtifact() { + logger.debug("MainValuesArtifact.MainValuesartifact()"); + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("MainValuesArtifact.setup"); + state = new StaticState(STATIC_STATE_NAME); + + Facet qfacet0 = new MainValuesQFacet( + DURATION_MAINVALUES_Q, + Resources.getMsg( + callMeta, + "facet.discharge_curves.mainvalues.q", + "facet.discharge_curves.mainvalues.q"), + false); + Facet qfacet1 = new MainValuesQFacet( + COMPUTED_DISCHARGE_MAINVALUES_Q, + Resources.getMsg( + callMeta, + "facet.discharge_curves.mainvalues.q", + "facet.discharge_curves.mainvalues.q"), + false); + Facet qfacet2 = new MainValuesQFacet( + MAINVALUES_Q, + Resources.getMsg( + callMeta, + "facet.discharge_curves.mainvalues.q", + "facet.discharge_curves.mainvalues.q"), + true); + Facet wfacet1 = new MainValuesWFacet( + COMPUTED_DISCHARGE_MAINVALUES_W, + Resources.getMsg( + callMeta, + "facet.discharge_curves.mainvalues.w", + "facet.discharge_curves.mainvalues.w"), + false); + Facet wfacet2 = new MainValuesWFacet( + MAINVALUES_W, + Resources.getMsg( + callMeta, + "facet.discharge_curves.mainvalues.w", + "facet.discharge_curves.mainvalues.w"), + true); + + List<Facet> fs = new ArrayList<Facet>(); + fs.add(qfacet0); + fs.add(qfacet1); + fs.add(qfacet2); + fs.add(wfacet1); + fs.add(wfacet2); + + facets.put(state.getID(), fs); + spawnState(); + super.setup(identifier, factory, context, callMeta, data); + } + + + /** + * Create "the" state. + */ + protected State spawnState() { + state = new StaticState(STATIC_STATE_NAME); + List<Facet> fs = (List<Facet>) facets.get(STATIC_STATE_NAME); + + DefaultOutput mainValuesOutput = new DefaultOutput( + "computed_discharge_curve", + "output.computed_discharge_curve", "image/png", + fs, + "chart"); + + state.getOutputs().add(mainValuesOutput); + return state; + } + + + @Override + protected void initialize(Artifact artifact, Object context, CallMeta meta) { + logger.debug("MainValuesArtifact.initialize"); + FLYSArtifact winfo = (FLYSArtifact) artifact; + double [] locations = FLYSUtils.getLocations(winfo); + if (locations != null) { + double location = locations[0]; + addData("location", new DefaultStateData("location", null, null, + String.valueOf(location))); + } + else { + logger.warn("No location for mainvalues given."); + } + importData(winfo, "river"); + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getState()); + return states; + } + + + /** + * Get the "current" state. + * @param cc ignored. + * @return the "current" state. + */ + @Override + public State getCurrentState(Object cc) { + return getState(); + } + + + /** + * Get the only possible state. + * @return the state. + */ + protected State getState() { + return getState(null, null); + } + + + /** + * Get the state. + * @param context ignored. + * @param stateID ignored. + * @return the state. + */ + @Override + protected State getState(Object context, String stateID) { + if (state != null) + return state; + else + return spawnState(); + } + + + /** + * Access the Gauge that the mainvalues are taken from. + * @return Gauge that main values are taken from or null in case of + * invalid parameterization. + */ + protected Gauge getGauge() { + River river = FLYSUtils.getRiver(this); + + // TODO use helper to get location as double + String locationStr = getDataAsString("location"); + + if (river == null || locationStr == null) { + return null; + } + + double location = Double.parseDouble(locationStr); + + return river.determineGaugeByPosition(location); + } + + + /** + * Get current location. + * @return the location. + */ + public double getLocation() { + double location = Double.parseDouble(getDataAsString("location")); + return location; + } + + + /** + * Get a list of "Q" main values. + * @return list of Q main values. + */ + public List<NamedDouble> getMainValuesQ(boolean atGauge) { + List<NamedDouble> filteredList = new ArrayList<NamedDouble>(); + Gauge gauge = getGauge(); + WstValueTable interpolator = WstValueTableFactory.getTable(FLYSUtils.getRiver(this)); + Calculation c = new Calculation(); + double w_out[] = {0.0f}; + double q_out[] = {0.0f}; + double kms[] = {getLocation()}; + double gaugeStation = gauge.getStation().doubleValue(); + if (gauge != null) { + List<MainValue> orig = gauge.getMainValues(); + for (MainValue mv : orig) { + if (mv.getMainValue().getType().getName().equals("Q")) { + if (atGauge) { + q_out[0] = mv.getValue().doubleValue(); + } + else { + interpolator.interpolate(mv.getValue().doubleValue(), + gaugeStation, kms, w_out, q_out, c); + } + filteredList.add(new NamedDouble( + mv.getMainValue().getName(), + q_out[0] + )); + } + } + } + return filteredList; + } + + + /** + * Get a list of "W" main values. + * @param atGauge if true, do not interpolate + * @return list of W main values. + */ + public List<NamedDouble> getMainValuesW(boolean atGauge) { + List<NamedDouble> filteredList = new ArrayList<NamedDouble>(); + Gauge gauge = getGauge(); + WstValueTable interpolator = WstValueTableFactory.getTable(FLYSUtils.getRiver(this)); + Calculation c = new Calculation(); + + double gaugeStation = gauge.getStation().doubleValue(); + double w_out[] = {0.0f}; + double q_out[] = {0.0f}; + double kms[] = {getLocation()}; + if (gauge != null) { + List<MainValue> orig = gauge.getMainValues(); + for (MainValue mv : orig) { + if (atGauge) { + if (mv.getMainValue().getType().getName().equals("W")) { + filteredList.add(new NamedDouble(mv.getMainValue().getName(), + mv.getValue().doubleValue())); + + } + } else + // We cannot interpolate the W values, so derive them + // from given Q values. + if (mv.getMainValue().getType().getName().equals("Q")) { + interpolator.interpolate(mv.getValue().doubleValue(), + gaugeStation, kms, w_out, q_out, c); + filteredList.add(new NamedDouble( + "W(" + mv.getMainValue().getName() +")", + w_out[0] + )); + } + } + } + return filteredList; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,142 @@ +package de.intevation.flys.artifacts; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.json.JSONArray; +import org.json.JSONException; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.geom.Lines; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.model.FastCrossSectionLine; + + +/** + * Artifact to store user-added points and water lines. + */ +public class ManualPointsArtifact +extends StaticFLYSArtifact +implements FacetTypes, WaterLineArtifact +{ + private static final long serialVersionUID = 7096025125474986011L; + + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(ManualPointsArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "manualpoints"; + + + public ManualPointsArtifact() { + logger.debug("ManualPointsArtifact.ManualPointsArtifact()"); + } + + + /** + * Gets called from factory to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("ManualPointsArtifact.setup"); + super.setup(identifier, factory, context, callMeta, data); + initialize(null, context, callMeta); + } + + + /** Return the name of this artifact. */ + @Override + public String getName() { + return ARTIFACT_NAME; + } + + + /** Access state data storing the jsonstring with points. */ + public String getPointsData(String facetName) { + return getDataAsString(facetName + ".data"); + } + + + /** + * Access state data storing the jsonstring with lines. + * @param facetName Name of facet or null if the so far + * only known case should be picked. + * @return (String) value of data element (expect json). + */ + public String getLinesData(String facetName) { + if (facetName == null) + return getDataAsString("cross_section.manualpoints.lines"); + // TODO .lineS? + return getDataAsString(facetName + ".line"); + } + + + /** Setup state and facet. */ + @Override + protected void initialize(Artifact artifact, Object context, CallMeta meta) { + logger.debug("ManualPointsArtifact.initialize"); + List<Facet> fs = new ArrayList<Facet>(); + + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in ManualPointsArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in ManualPointsArtifact.initialize (" + + state.getID() + ")."); + } + } + + + /** + * Get value of line at index. + * @param index index in json array defining lines. + * @return water height of line at given index. + */ + protected double getLine(int index) { + try { + JSONArray lines = new JSONArray(getLinesData(null)); + JSONArray array = lines.getJSONArray(index); + + return array.getDouble(0); + } + catch(JSONException e){ + logger.error("Could not decode json for line."); + return 0d; + } + } + + + /** + * Get the water line "surface". + * @param index index of facets data. + * @param csl 'ground' against which to determine water surface. + * @param a (ignored in this implementation). + * @param b (ignored in this implementation). + */ + @Override + public Lines.LineData getWaterLines( + int index, + FastCrossSectionLine csl, + double a, double b + ) { + List<Point2D> points = csl.getPoints(); + return Lines.createWaterLines(points, getLine(index)); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/MapArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,200 @@ +package de.intevation.flys.artifacts; + +import org.apache.log4j.Logger; + +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.ArtifactNamespaceContext; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifactdatabase.state.Output; + +import de.intevation.flys.model.River; +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.RiverAxisArtifact.RiverAxisState; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet; + + +public class MapArtifact extends FLYSArtifact { + + private static final Logger logger = + Logger.getLogger(MapArtifact.class); + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callmeta, + Document data) + { + logger.debug("MapArtifact.setup"); + this.identifier = identifier; + name = "new_map"; + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + + List<State> states = getStates(context); + + setCurrentState(states.get(0)); + } + + + @Override + protected void appendBackgroundActivity( + ElementCreator cr, + Element root, + CallContext context + ) { + Element inBackground = cr.create("background-processing"); + root.appendChild(inBackground); + + cr.addAttr( + inBackground, + "value", + String.valueOf(context.isInBackground()), + true); + } + + + /** + * Append output mode nodes to a document. + */ + @Override + protected void appendOutputModes( + Document doc, + Element outs, + CallContext context, + String uuid) + { + List<String> stateIds = getPreviousStateIds(); + + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + for (String stateId: stateIds) { + logger.debug("Append output modes for state: " + stateId); + DefaultState state = (DefaultState) engine.getState(stateId); + + List<Output> list = state.getOutputs(); + if (list == null || list.isEmpty()) { + logger.debug("-> No output modes for this state."); + continue; + } + + List<Facet> fs = facets.get(stateId); + + if (fs == null || fs.isEmpty()) { + logger.debug("No facets for previous state found."); + continue; + } + + logger.debug("Found " + fs.size() + " facets in previous states."); + + List<Output> generated = generateOutputs(list, fs); + + ProtocolUtils.appendOutputModes(doc, outs, generated); + } + + try { + DefaultState cur = (DefaultState) getCurrentState(context); + if (cur.validate(this)) { + List<Output> list = cur.getOutputs(); + if (list != null && list.size() > 0) { + logger.debug( + "Append output modes for current state: " + cur.getID()); + + List<Facet> fs = facets.get(cur.getID()); + + if (fs != null && fs.size() > 0) { + List<Output> generated = generateOutputs(list, fs); + + logger.debug("Found " + fs.size() + " current facets."); + if (!generated.isEmpty()) { + ProtocolUtils.appendOutputModes( + doc, outs, generated); + } + } + else { + logger.debug("No facets found for the current state."); + } + } + } + } + catch (IllegalArgumentException iae) { + // state is not valid, so we do not append its outputs. + } + } + + public static class MapState extends RiverAxisState { + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old) + { + logger.debug("MapState.computeAdvance"); + + this.artifact = artifact; + + String type = getFacetType(); + + WMSDBLayerFacet facet = new WMSDBLayerFacet( + 0, + type, + getTitle(context.getMeta()), + ComputeType.ADVANCE, + getID(), hash, + getUrl()); + + String name = type + "-" + artifact.identifier(); + + facet.addLayer(name); + facet.setExtent(getExtent()); + facet.setSrid(getSrid()); + facet.setData(getDataString()); + facet.setFilter(getFilter()); + facet.setGeometryType(getGeometryType()); + facet.setConnection(getConnection()); + facet.setConnectionType(getConnectionType()); + facet.setLabelItem(getLabelItem()); + + facets.add(facet); + + return null; + } + + @Override + public int getRiverId() { + River r = FLYSUtils.getRiver(artifact); + int riverId = r.getId(); + + return riverId; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.GaugeFinder; +import de.intevation.flys.artifacts.model.GaugeFinderFactory; +import de.intevation.flys.artifacts.model.GaugeRange; +import de.intevation.flys.artifacts.model.NamedDouble; + +import de.intevation.flys.artifacts.services.FixingsKMChartService; + +import de.intevation.flys.artifacts.states.DefaultState; + +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * Artifact to produce sector markers. + */ +public class QSectorArtifact +extends StaticFLYSArtifact +{ + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(QSectorArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "qsector"; + + + /** + * Trivial Constructor. + */ + public QSectorArtifact() { + logger.debug("QSectorArtifact.QSectorArtifact()"); + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("QSectorArtifact.setup"); + super.setup(identifier, factory, context, callMeta, data); + initialize(null, context, callMeta); + } + + + /** Return the name of this artifact. */ + public String getName() { + return ARTIFACT_NAME; + } + + + /** Get list of NamedDouble s (QSectors). */ + public Object getQSectors(double km, CallContext context) { + + String river = getDataAsString("river"); + List<NamedDouble> qsectors = new ArrayList<NamedDouble>(); + + GaugeFinderFactory ggf = GaugeFinderFactory.getInstance(); + GaugeFinder gf = ggf.getGaugeFinder(river); + + if (gf == null) { + logger.warn("No gauge finder found for river '" + river + "'"); + return null; + } + + GaugeRange gr = gf.find(km); + if (gr == null) { + logger.debug("No gauge range found for km " + + km + " on river " + river + "."); + return null; + } + + if (logger.isDebugEnabled()) { + logger.debug(gr); + } + + for (int i = 0; i < FixingsKMChartService.I18N_Q_SECTOR_BOARDERS.length; ++i) { + String key = FixingsKMChartService.I18N_Q_SECTOR_BOARDERS[i]; + String def = FixingsKMChartService.DEFAULT_Q_SECTOR_BORDERS[i]; + String label = Resources.getMsg(context.getMeta(), key, def); + + qsectors.add(new NamedDouble(label, gr.getSectorBorder(i))); + } + + return qsectors; + } + + + /** Setup state and facet. */ + @Override + protected void initialize(Artifact artifact, Object context, CallMeta meta) { + logger.debug("QSectorArtifact.initialize"); + List<Facet> fs = new ArrayList<Facet>(); + + FLYSArtifact flys = (FLYSArtifact) artifact; + importData(flys, "river"); + + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in QSectorArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in QSectorArtifact.initialize (" + + state.getID() + ")."); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,152 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class RiverAxisArtifact extends WMSDBArtifact { + + public static final String NAME = "riveraxis"; + + + private static final Logger logger = + Logger.getLogger(RiverAxisArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("RiverAxisArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new RiverAxisState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class RiverAxisState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(RiverAxisState.class); + + protected Geometry geom; + protected int riverId; + + public RiverAxisState(){} + + public RiverAxisState(FLYSArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + + try { + riverId = Integer.parseInt(ids); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + ids + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_RIVERAXIS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + River river = RiverFactory.getRiver(getRiverId()); + return GeometryUtils.transform( + GeometryUtils.getRiverBoundary(river.getName()), + getSrid()); + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()); + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM river_axes USING SRID " + srid; + } + else { + return "geom FROM river_axes USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,123 @@ +package de.intevation.flys.artifacts; + +import java.util.Collection; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.data.StateData; +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +/** + * A basic FLYSArtifact. + */ +public abstract class StaticFLYSArtifact extends FLYSArtifact { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(StaticFLYSArtifact.class); + + /** Path to 'ids' (data) in doc that comes from datacage. */ + public static final String XPATH_IDS = "/art:action/art:ids/@value"; + + /** + * Create description document which includes outputmodes. + * @param data ignored. + */ + @Override + public Document describe(Document data, CallContext cc) { + logger.debug("Describe artifact: " + identifier()); + + Document desc = XMLUtils.newDocument(); + + ElementCreator creator = new ElementCreator( + desc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = ProtocolUtils.createRootNode(creator); + desc.appendChild(root); + + ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash()); + root.appendChild(createOutputModes(cc, desc, creator)); + + // Add the data to an anonymous state. + Collection<StateData> datas = this.data.values(); + if (datas.size() > 0) { + Element ui = creator.create("ui"); + Element staticE = creator.create("static"); + Element state = creator.create("state"); + ui.appendChild(staticE); + staticE.appendChild(state); + root.appendChild(ui); + + for (StateData dataItem : datas) { + Element itemelent = creator.create("data"); + creator.addAttr(itemelent, "name", dataItem.getName(), true); + creator.addAttr(itemelent, "type", dataItem.getType(), true); + state.appendChild(itemelent); + Element valuement = creator.create("item"); + creator.addAttr(valuement, "label", dataItem.getDescription(), true); + creator.addAttr(valuement, "value", dataItem.getValue().toString(), true); + itemelent.appendChild(valuement); + } + } + + return desc; + } + + + /** + * Return the value of id element in Datacage data document. + * @param data Document as passed by datacage. + * @return the id element value of data document. + */ + public static String getDatacageIDValue(Document data) { + return XMLUtils.xpathString(data, XPATH_IDS, + ArtifactNamespaceContext.INSTANCE); + } + + + protected Element createOutputModes( + CallContext cc, + Document doc, + ElementCreator creator) + { + Element outs = ProtocolUtils.createArtNode( + creator, "outputmodes", null, null); + + State state = getCurrentState(cc); + List<Output> list = state.getOutputs(); + + if (list != null && list.size() > 0) { + List<Facet> fs = facets.get(state.getID()); + if (fs != null && fs.size() > 0) { + List<Output> generated = generateOutputs(list, fs); + + logger.debug("Found " + fs.size() + " current facets."); + if (!generated.isEmpty()) { + ProtocolUtils.appendOutputModes( + doc, outs, generated); + } + } + else { + logger.debug("No facets found for the current state."); + } + } + + return outs; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,384 @@ +package de.intevation.flys.artifacts; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.geom.Lines; + +import de.intevation.flys.artifacts.math.Distance; +import de.intevation.flys.artifacts.math.Linear; + +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RelativePointFacet; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WKmsFacet; +import de.intevation.flys.artifacts.model.WKmsFactory; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.artifacts.states.StaticState; + +import de.intevation.flys.model.FastCrossSectionLine; + +import java.awt.geom.Point2D; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +/** + * Artifact to access additional "waterlevel"-type of data, like the height + * of protective measures (dikes). + * + * This artifact neglects (Static)FLYSArtifacts capabilities of interaction + * with the StateEngine by overriding the getState*-methods. + */ +public class StaticWKmsArtifact +extends StaticFLYSArtifact +implements FacetTypes, WaterLineArtifact +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(StaticWKmsArtifact.class); + + private static final String NAME = "staticwkms"; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(NAME, FacetActivity.INACTIVE); + } + + public static final String STATIC_STATE_NAME = + "state.additional_wkms.static"; + + /** Data Item name to know whether we are Heighmarks and reveive + * some data slightly different. */ + public static final String DATA_HEIGHT_TYPE = + "height_marks"; + + /** One and only state to be in. */ + protected transient State state = null; + + + /** + * Trivial Constructor. + */ + public StaticWKmsArtifact() { + logger.debug("StaticWKmsArtifact.StaticWKmsArtifact"); + } + + @Override + public String getName() { + return NAME; + } + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("StaticWKmsArtifact.setup"); + + state = new StaticState(STATIC_STATE_NAME); + + if (logger.isDebugEnabled()) { + logger.debug(XMLUtils.toString(data)); + } + + List<Facet> fs = new ArrayList<Facet>(); + String code = getDatacageIDValue(data); + + // TODO Go for JSON, one day. + //ex.: flood_protection-wstv-114-12 + if (code != null) { + String [] parts = code.split("-"); + + if (parts.length >= 4) { + int col = -1; + int wst = Integer.parseInt(parts[3]); + + if (!parts[2].equals("A")) { + col = Integer.parseInt(parts[2]); + } + + addStringData("col_pos", parts[2]); + addStringData("wst_id", parts[3]); + + String wkmsName; + if (col >= 0) { + wkmsName = WKmsFactory.getWKmsName(col, wst); + } + else { + wkmsName = WKmsFactory.getWKmsName(wst); + } + + String name; + if (parts[0].equals(HEIGHTMARKS_POINTS)) { + name = HEIGHTMARKS_POINTS; + addStringData(DATA_HEIGHT_TYPE, "true"); + } + else { + name = STATIC_WKMS; + } + + String facetDescription = Resources.getMsg( + callMeta, wkmsName, wkmsName); + Facet wKmsFacet = new WKmsFacet( + name, + facetDescription); + Facet csFacet = new CrossSectionWaterLineFacet(0, + facetDescription); + Facet rpFacet = new RelativePointFacet(facetDescription); + + fs.add(wKmsFacet); + fs.add(csFacet); + fs.add(rpFacet); + facets.put(state.getID(), fs); + } + } + + spawnState(); + super.setup(identifier, factory, context, callMeta, data); + } + + + /** + * Initialize the static state with output. + * @return static state + */ + protected State spawnState() { + state = new StaticState(STATIC_STATE_NAME); + List<Facet> fs = facets.get(STATIC_STATE_NAME); + DefaultOutput output = new DefaultOutput( + "general", + "general", "image/png", + fs, + "chart"); + + state.getOutputs().add(output); + return state; + } + + + /** + * Called via setup. + * + * @param artifact The master-artifact. + */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + logger.debug("StaticWKmsArtifact.initialize"); + FLYSArtifact winfo = (FLYSArtifact) artifact; + // TODO: The river is of no interest, so far. + addData("river", winfo.getData("river")); + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getState()); + return states; + } + + + /** + * Get the "current" state (there is but one). + * @param cc ignored. + * @return the "current" (only possible) state. + */ + @Override + public State getCurrentState(Object cc) { + return getState(); + } + + + /** + * Get the only possible state. + * @return the state. + */ + protected State getState() { + return getState(null, null); + } + + + /** + * Get the state. + * @param context ignored. + * @param stateID ignored. + * @return the state. + */ + @Override + protected State getState(Object context, String stateID) { + return (state != null) + ? state + : spawnState(); + } + + + /** + * Get WKms from factory. + * @param idx param is not needed (TODO?) + * @return WKms according to parameterization (can be null); + */ + public WKms getWKms(int idx) { + logger.debug("StaticWKmsArtifact.getWKms"); + + return WKmsFactory.getWKms( + Integer.parseInt(getDataAsString("col_pos")), + Integer.parseInt(getDataAsString("wst_id"))); + } + + + /** + * Returns W at Km of WKms, linearly interpolated. + * Returns -1 if not found. + */ + public static double getWAtKmLin(WKms wkms, double km) { + // Uninformed search. + int size = wkms.size(); + int idx = 0; + boolean kmIncreasing = (wkms.getKm(0) < wkms.getKm(wkms.size()-1)) + ? true : false; + if (kmIncreasing) { + while (idx < size && wkms.getKm(idx) < km) { + idx++; + } + } + else { + idx = wkms.size() -1; + while (idx > 0 && wkms.getKm(idx) > km) { + idx--; + } + } + + if (idx == size -1 || idx == 0) { + return -1; + } + + // Do linear interpolation + int mod = kmIncreasing ? -1 : +1; + return Linear.linear(km, wkms.getKm(idx+mod), wkms.getKm(idx), wkms.getW(idx+mod), wkms.getW(idx)); + } + + + /** + * Get the W at a specific km, only if it is closer to km than to any of + * the other given km. + * Return Double.NaN otherwise + * + * @param wkms WKms in which to search for a spatially close W value. + * @param km the input km, which is compared to values from wkms. + * @param next the next available input km (-1 if unavailable). + * @param prev the previous available input km (-1 if unavailable). + * + * @return W in wkms that is closer to km than to next and prev, or Double.NaN. + */ + public double getWAtCloseKm(WKms wkms, double km, double next, double prev) { + int size = wkms.size(); + for (int i = 0; i < size; i++) { + double wkmsKm = wkms.getKm(i); + double dist = Distance.distance(wkmsKm, km); + if ((prev == -1d || dist <= Distance.distance(wkmsKm, prev)) + && (next == -1d || dist <= Distance.distance(wkmsKm, next))) { + return wkms.getW(i); + } + } + + return Double.NaN; + } + + + /** + * Returns W at Km of WKms, searching linearly. + * Returns -1 if not found. + * @param wkms the WKms object to search for given km. + * @param km The searched km. + * @return W at given km if in WKms, -1 if not found. + */ + public static double getWAtKm(WKms wkms, double km) { + // Uninformed search, intolerant. + double TOLERANCE = 0.0d; + int size = wkms.size(); + for (int i = 0; i < size; i++) { + if (Distance.within(wkms.getKm(i), km, TOLERANCE)) { + return wkms.getW(i); + } + } + + return -1; + } + + + /** + * Get points of line describing the surface of water at cross section. + * + * @param idx Index of facet and in wkms array. + * @param csl FastCrossSectionLine to compute water surface agains. + * @param next The km of the next crosssectionline. + * @param prev The km of the previous crosssectionline. + * + * @return an array holding coordinates of points of surface of water ( + * in the form {{x1, x2}, {y1, y2}} ). + */ + @Override + public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, + double next, double prev + ) { + logger.debug("getWaterLines(" + idx + ")/" + identifier()); + + List<Point2D> points = csl.getPoints(); + + WKms wkms = getWKms(0); + + double km = csl.getKm(); + + // Find W at km. + double wAtKm; + + // If heightmarks, only deliver if data snaps. + if (getDataAsString(DATA_HEIGHT_TYPE) != null && + getDataAsString(DATA_HEIGHT_TYPE).equals("true")) { + wAtKm = getWAtCloseKm(wkms, km, next, prev); + } + else { + wAtKm = getWAtKm(wkms, km); + } + + if (wAtKm == -1 || Double.isNaN(wAtKm)) { + logger.warn("Waterlevel at km " + km + " unknown."); + return new Lines.LineData(new double[][] {{}}, 0d, 0d); + } + + return Lines.createWaterLines(points, wAtKm); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,155 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WKmsFactory; +import de.intevation.flys.artifacts.model.WQKmsFactory; + +import de.intevation.flys.artifacts.states.DefaultState; + + +/** + * Artifact to access additional "waterlevel/discharge"-type of data, like + * fixation measurements. + * + * This artifact neglects (Static)FLYSArtifacts capabilities of interaction + * with the StateEngine by overriding the getState*-methods. + */ +public class StaticWQKmsArtifact +extends StaticFLYSArtifact +implements FacetTypes +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(StaticWQKmsArtifact.class); + + public static final String STATIC_STATE_NAME = + "state.additional_wqkms.static"; + + private static final String NAME = "staticwqkms"; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(NAME, FacetActivity.INACTIVE); + } + + /** + * Trivial Constructor. + */ + public StaticWQKmsArtifact() { + logger.debug("StaticWQKmsArtifact.StaticWQKmsArtifact"); + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("StaticWQKmsArtifact.setup"); + + // Store the 'ids' (from datacage). + if (logger.isDebugEnabled()) { + logger.debug("StaticWQKmsArtiact.setup" + XMLUtils.toString(data)); + } + + String code = getDatacageIDValue(data); + addStringData("ids", code); + if (code != null) { + String [] parts = code.split("-"); + + if (parts.length >= 4) { + int col = Integer.parseInt(parts[2]); + int wst = Integer.parseInt(parts[3]); + + addStringData("col_pos", parts[2]); + addStringData("wst_id", parts[3]); + } + } + + // Do this AFTER we have set the col_pos etc. + super.setup(identifier, factory, context, callMeta, data); + } + + + /** + * Called via setup. + * + * @param artifact The master-artifact. + */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + logger.debug("StaticWQKmsArtifact.initialize"); + WINFOArtifact winfo = (WINFOArtifact) artifact; + // TODO: The river is of no interest, so far., also use importData + importData(winfo, "river"); + + List<Facet> fs = new ArrayList<Facet>(); + + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in StaticWQKmsArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in StaticWQKmsArtifact.initialize (" + + state.getID() + ")."); + } + } + + + /** + * Get WQKms from factory. + * @return WQKms according to parameterization (can be null); + */ + public WQKms getWQKms() { + logger.debug("StaticWQKmsArtifact.getWQKms"); + + int col = Integer.parseInt(getDataAsString("col_pos")); + int wst = Integer.parseInt(getDataAsString("wst_id")); + + /** TODO do not run twice against db to do this. */ + String wkmsName = WKmsFactory.getWKmsName(col, wst); + + WQKms res = WQKmsFactory.getWQKms(col, wst); + res.setName(wkmsName); + return res; + } + + /** Return specific name. */ + @Override + public String getName() { + return NAME; + } + + // TODO implement deepCopy. +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1185 @@ +package de.intevation.flys.artifacts; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.StringUtils; + +import de.intevation.flys.artifacts.geom.Lines; + +import de.intevation.flys.artifacts.model.Calculation1; +import de.intevation.flys.artifacts.model.Calculation2; +import de.intevation.flys.artifacts.model.Calculation3; +import de.intevation.flys.artifacts.model.Calculation4; +import de.intevation.flys.artifacts.model.Calculation5; +import de.intevation.flys.artifacts.model.Calculation6; +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DischargeTables; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Segment; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WW; +import de.intevation.flys.artifacts.model.WstValueTable; +import de.intevation.flys.artifacts.model.WstValueTableFactory; + +import de.intevation.flys.artifacts.states.LocationDistanceSelect; + +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.FastCrossSectionLine; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.DoubleUtil; +import de.intevation.flys.utils.FLYSUtils; + +import gnu.trove.TDoubleArrayList; + +import java.awt.geom.Point2D; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + + +/** + * The default WINFO artifact. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WINFOArtifact +extends FLYSArtifact +implements FacetTypes, WaterLineArtifact { + + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(WINFOArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "winfo"; + + /** XPath */ + public static final String XPATH_STATIC_UI ="/art:result/art:ui/art:static"; + + /** The default number of steps between the start end end of a selected Q + * range. */ + public static final int DEFAULT_Q_STEPS = 30; + + /** The default step width between the start end end kilometer. */ + public static final double DEFAULT_KM_STEPS = 0.1; + + private static final String [] INACTIVES = new String[] { + LONGITUDINAL_Q, + DURATION_Q + }; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance().register( + ARTIFACT_NAME, + new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String outputName + ) { + String fname = facet.getName(); + if ((fname.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) + || fname.equals(COMPUTED_DISCHARGE_MAINVALUES_W)) + && outputName.equals("computed_discharge_curve")) { + return Boolean.FALSE; + } + return !StringUtils.contains(fname, INACTIVES); + + } + }); + } + + /** + * The default constructor. + */ + public WINFOArtifact() { + } + + + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + @Override + public String getName() { + return ARTIFACT_NAME; + } + + protected static boolean reportGeneratedWs( + Calculation report, + double [] ws + ) { + if (ws == null || ws.length < 2) { + return false; + } + + double lastW = ws[0]; + boolean alreadyReported = false; + + for (int i = 1; i < ws.length; ++i) { + if (Math.abs(lastW - ws[i]) < 1e-5) { + if (!alreadyReported) { + alreadyReported = true; + report.addProblem("more.than.one.q.for.w", ws[i]); + } + } + else { + alreadyReported = false; + } + lastW = ws[i]; + } + + return true; + } + + + // + // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES + // + + /** + * Returns the data that is computed by a waterlevel computation. + * + * @return an array of data triples that consist of W, Q and Kms. + */ + public CalculationResult getWaterlevelData() + { + logger.debug("WINFOArtifact.getWaterlevelData"); + + if (getDataAsString("calculation_mode") + .equals("calc.discharge.longitudinal.section") + ) { + return getDischargeLongitudinalSectionData(); + } + + River river = FLYSUtils.getRiver(this); + if (river == null) { + return error(new WQKms[0], "no.river.selected"); + } + + double[] kms = getKms(); + if (kms == null) { + return error(new WQKms[0], "no.kms.selected"); + } + + double[] qs = getQs(); + double[] ws = null; + boolean qSel = true; + + Calculation report = new Calculation(); + + if (qs == null) { + logger.debug("Determine Q values based on a set of W values."); + qSel = false; + ws = getWs(); + double [][] qws = getQsForWs(ws); + if (qws == null || qws.length == 0) { + return error(new WQKms[0], "converting.ws.to.qs.failed"); + } + qs = qws[0]; + + if (reportGeneratedWs(report, qws[1])) { + ws = qws[1]; + } + } + + WstValueTable wst = WstValueTableFactory.getTable(river); + if (wst == null) { + return error(new WQKms[0], "no.wst.for.selected.river"); + } + + + double [] range = FLYSUtils.getKmRange(this); + if (range == null) { + return error(new WQKms[0], "no.range.found"); + } + + double refKm; + + if (isFreeQ() || isFreeW()) { + refKm = range[0]; + logger.debug("'free' calculation (km " + refKm + ")"); + } + else { + Gauge gauge = river.determineGaugeByPosition(range[0]); + if (gauge == null) { + return error( + new WQKms[0], "no.gauge.found.for.km"); + } + + refKm = gauge.getStation().doubleValue(); + + logger.debug( + "reference gauge: " + gauge.getName() + " (km " + refKm + ")"); + } + + return computeWaterlevelData(kms, qs, ws, wst, refKm, report); + } + + + /** + * Computes the data of a waterlevel computation based on the interpolation + * in WstValueTable. + * + * @param kms The kilometer values. + * @param qs The discharge values. + * @param wst The WstValueTable used for the interpolation. + * + * @return an array of data triples that consist of W, Q and Kms. + */ + public static CalculationResult computeWaterlevelData( + double [] kms, + double [] qs, + double [] ws, + WstValueTable wst, + double refKm, + Calculation report + ) { + logger.info("WINFOArtifact.computeWaterlevelData"); + + Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm); + + if (report != null) { + calc1.addProblems(report); + } + + return calc1.calculate(wst); + } + + + /** + * Returns the data that is computed by a duration curve computation. + * + * @return the data computed by a duration curve computation. + */ + public CalculationResult getDurationCurveData() { + logger.debug("WINFOArtifact.getDurationCurveData"); + + River r = FLYSUtils.getRiver(this); + + if (r == null) { + return error(null, "no.river.selected"); + } + + Gauge g = getGauge(); + + if (g == null) { + return error(null, "no.gauge.selected"); + } + + double[] locations = FLYSUtils.getLocations(this); + + if (locations == null) { + return error(null, "no.locations.selected"); + } + + WstValueTable wst = WstValueTableFactory.getTable(r); + if (wst == null) { + return error(null, "no.wst.for.river"); + } + + return computeDurationCurveData(g, wst, locations[0]); + } + + + /** + * Computes the data used to create duration curves. + * + * @param gauge The selected gauge. + * @param location The selected location. + * + * @return the computed data. + */ + public static CalculationResult computeDurationCurveData( + Gauge gauge, + WstValueTable wst, + double location) + { + logger.info("WINFOArtifact.computeDurationCurveData"); + + Object[] obj = gauge.fetchDurationCurveData(); + + int[] days = (int[]) obj[0]; + double[] qs = (double[]) obj[1]; + + Calculation3 calculation = new Calculation3(location, days, qs); + + return calculation.calculate(wst); + } + + + /** + * Returns the data that is computed by a discharge curve computation. + * + * @return the data computed by a discharge curve computation. + */ + public CalculationResult getComputedDischargeCurveData() + throws NullPointerException + { + logger.debug("WINFOArtifact.getComputedDischargeCurveData"); + + River r = FLYSUtils.getRiver(this); + + if (r == null) { + return error(new WQKms[0], "no.river.selected"); + } + + double[] locations = FLYSUtils.getLocations(this); + + if (locations == null) { + return error(new WQKms[0], "no.locations.selected"); + } + + WstValueTable wst = WstValueTableFactory.getTable(r); + if (wst == null) { + return error(new WQKms[0], "no.wst.for.river"); + } + + return computeDischargeCurveData(wst, locations[0]); + } + + + /** + * Computes the data used to create computed discharge curves. + * + * @param wst The WstValueTable that is used for the interpolation (river- + * bound). + * @param location The location where the computation should be based on. + * + * @return an object that contains tuples of W/Q values at the specified + * location. + */ + public static CalculationResult computeDischargeCurveData( + WstValueTable wst, + double location) + { + logger.info("WINFOArtifact.computeDischargeCurveData"); + + Calculation2 calculation = new Calculation2(location); + + return calculation.calculate(wst); + } + + + /** Create CalculationResult with data and message. */ + protected static final CalculationResult error(Object data, String msg) { + return new CalculationResult(data, new Calculation(msg)); + } + + + /** + * Returns the data computed by the discharge longitudinal section + * computation. + * + * @return an array of WQKms object - one object for each given Q value. + */ + public CalculationResult getDischargeLongitudinalSectionData() { + + logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData"); + + River river = FLYSUtils.getRiver(this); + if (river == null) { + logger.debug("No river selected."); + return error(new WQKms[0], "no.river.selected"); + } + + WstValueTable table = WstValueTableFactory.getTable(river); + if (table == null) { + logger.debug("No wst found for selected river."); + return error(new WQKms[0], "no.wst.for.river"); + } + + List<Segment> segments = getSegments(); + + if (segments == null) { + logger.debug("Cannot create segments."); + return error(new WQKms[0], "cannot.create.segments"); + } + + double [] range = getFromToStep(); + + if (range == null) { + logger.debug("Cannot figure out range."); + return error(new WQKms[0], "no.range.found"); + } + + Calculation4 calc4 = new Calculation4(segments, river, isQ()); + + return calc4.calculate(table, range[0], range[1], range[2]); + } + + + /** + * Returns the data that is computed by a reference curve computation. + * + * @return the data computed by a reference curve computation. + */ + public CalculationResult getReferenceCurveData(CallContext context) { + + Double startKm = getReferenceStartKm(); + + if (startKm == null) { + return error(new WW[0], "no.reference.start.km"); + } + + double [] endKms = getReferenceEndKms(); + + if (endKms == null || endKms.length == 0) { + return error(new WW[0], "no.reference.end.kms"); + } + + Calculation5 calc5 = new Calculation5(startKm, endKms); + + River r = FLYSUtils.getRiver(this); + if (r == null) { + return error(new WW[0], "no.river.found"); + } + + WstValueTable wst = WstValueTableFactory.getTable(r); + if (wst == null) { + return error(new WW[0], "no.wst.for.river"); + } + + Map<Double, Double> kms2gaugeDatums = r.queryGaugeDatumsKMs(); + + return calc5.calculate(wst, kms2gaugeDatums, context); + } + + + /** Get reference (start) km. */ + public Double getReferenceStartKm() { + StateData sd = getData("reference_startpoint"); + + if (sd == null) { + logger.warn("no reference start given."); + return null; + } + + logger.debug("Reference start km given: " + sd.getValue()); + + String input = (String) sd.getValue(); + + if (input == null || (input = input.trim()).length() == 0) { + logger.warn("reference start string is empty."); + return null; + } + + try { + return Double.valueOf(input); + } + catch (NumberFormatException nfe) { + logger.warn("reference start string is not numeric."); + } + + return null; + } + + + /** + * Get end kms for reference curve (null if none). + */ + public double [] getReferenceEndKms() { + StateData sd = getData("reference_endpoint"); + + if (sd == null) { + logger.warn("no reference end given."); + return null; + } + else { + logger.debug("Reference end km : " + sd.getValue()); + } + + String input = (String) sd.getValue(); + + if (input == null || (input = input.trim()).length() == 0) { + logger.warn("reference end string is empty."); + return null; + } + + TDoubleArrayList endKms = new TDoubleArrayList(); + + for (String part: input.split("\\s+")) { + try { + double km = Double.parseDouble(part); + if (!endKms.contains(km)) { + endKms.add(km); + } + } + catch (NumberFormatException nfe) { + logger.warn("reference end string is not numeric."); + } + } + + return endKms.toNativeArray(); + } + + + public CalculationResult getHistoricalDischargeData() { + Gauge gauge = FLYSUtils.getReferenceGauge(this); + String rawTimerange = getDataAsString("year_range"); + String rawValues = getDataAsString("historical_values"); + int mode = getDataAsInteger("historical_mode"); + + long[] timerange = FLYSUtils.longArrayFromString(rawTimerange); + double[] values = FLYSUtils.doubleArrayFromString(rawValues); + + Calendar start = new GregorianCalendar(); + start.setTimeInMillis(timerange[0]); + Calendar end = new GregorianCalendar(); + end.setTimeInMillis(timerange[1]); + + Calculation6 calc = new Calculation6( + mode, + new long[] { start.getTimeInMillis(), end.getTimeInMillis() }, + values); + + return calc.calculate(gauge); + } + + + public List<Segment> getSegments() { + StateData wqValues = getData("wq_values"); + if (wqValues == null) { + logger.warn("no wq_values given"); + return Collections.<Segment>emptyList(); + } + String input = (String) wqValues.getValue(); + if (input == null || (input = input.trim()).length() == 0) { + logger.warn("wq_values are empty"); + return Collections.<Segment>emptyList(); + } + return Segment.parseSegments(input); + } + + + /** + * Get corrected waterline against surface/profile. + */ + public Lines.LineData waterLineC(int idx, FastCrossSectionLine csl) { + List<Point2D> points = csl.getPoints(); + + WQKms[] wqckms = (WQKms[]) + getDischargeLongitudinalSectionData().getData(); + + // Find index of km. + double wishKM = csl.getKm(); + + // Find W/C at km, linear naive approach. + WQCKms triple = (WQCKms) wqckms[idx-1]; + + int old_idx = 0; + + if (triple.size() == 0) { + logger.warn("Calculation of c/waterline is empty."); + return Lines.createWaterLines(points, 0.0f); + } + + // Linear seach in WQKms for closest km. + double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); + double last_c = triple.getC(0); + + for (int i = 0, T = triple.size(); i < T; i++) { + double diff = Math.abs(wishKM - triple.getKm(i)); + if (diff > old_dist_wish) { + break; + } + last_c = triple.getC(i); + old_dist_wish = diff; + } + + return Lines.createWaterLines(points, last_c); + } + + + /** + * Get points of line describing the surface of water at cross section. + * + * @param idx Index for getWaterlevelData. + * @param csl The profile/surface to fill with water. + * @param nextIgnored Ignored in this implementation of WaterLineArtifact. + * @param prevIgnored Ignored in this implementation of WaterLineArtifact. + * + * @return an array holding coordinates of points of surface of water ( + * in the form {{x1, x2} {y1, y2}} ). + */ + @Override + public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, + double nextIgnored, double prevIgnored) { + logger.debug("getWaterLines(" + idx + ")"); + + List<Point2D> points = csl.getPoints(); + + // Need W at km + WQKms [] wqkms = (WQKms[]) getWaterlevelData().getData(); + if (wqkms.length == 0) { + logger.error("No WQKms found."); + return Lines.createWaterLines(points, 0.0f); + } + + if (wqkms.length <= idx) { + logger.error("getWaterLines() requested index (" + + idx + " not found."); + return waterLineC(idx, csl); + } + + // Find index of km. + double wishKM = csl.getKm(); + + // Find W at km, linear naive approach. + WQKms triple = wqkms[idx]; + + int old_idx = 0; + + if (triple.size() == 0) { + logger.warn("Calculation of waterline is empty."); + return Lines.createWaterLines(points, 0.0f); + } + + // Linear seach in WQKms for closest km. + double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); + double last_w = triple.getW(0); + + for (int i = 0, T = triple.size(); i < T; i++) { + double diff = Math.abs(wishKM - triple.getKm(i)); + if (diff > old_dist_wish) { + break; + } + last_w = triple.getW(i); + old_dist_wish = diff; + } + + return Lines.createWaterLines(points, last_w); + } + + + /** + * Returns the Qs for a number of Ws. This method makes use of + * DischargeTables.getQForW(). + * + * @param ws An array of W values. + * + * @return an array of Q values. + */ + public double [][] getQsForWs(double[] ws) { + + if (ws == null) { + logger.error("getQsForWs: ws == null"); + return null; + } + + boolean debug = logger.isDebugEnabled(); + + if (debug) { + logger.debug("FLYSArtifact.getQsForWs"); + } + + River r = FLYSUtils.getRiver(this); + if (r == null) { + logger.warn("no river found"); + return null; + } + + double [] range = FLYSUtils.getKmRange(this); + if (range == null) { + logger.warn("no ranges found"); + return null; + } + + if (isFreeW()) { + logger.debug("Bezugslinienverfahren I: W auf freier Strecke"); + // The simple case of the "Bezugslinienverfahren" + // "W auf freier Strecke". + WstValueTable wst = WstValueTableFactory.getTable(r); + if (wst == null) { + logger.warn("no wst value table found"); + return null; + } + double km = range[0]; + + TDoubleArrayList outQs = new TDoubleArrayList(ws.length); + TDoubleArrayList outWs = new TDoubleArrayList(ws.length); + + boolean generatedWs = false; + + for (int i = 0; i < ws.length; ++i) { + double w = ws[i]; + if (debug) { + logger.debug("getQsForWs: lookup Q for W: " + w); + } + // There could bemore than one Q per W. + double [] qs = wst.findQsForW(km, w); + for (int j = 0; j < qs.length; ++j) { + outWs.add(ws[i]); + outQs.add(qs[j]); + } + generatedWs |= qs.length != 1; + } + + if (debug) { + logger.debug("getQsForWs: number of Qs: " + outQs.size()); + } + + return new double [][] { + outQs.toNativeArray(), + generatedWs ? outWs.toNativeArray() : null }; + } + + if (debug) { + logger.debug("range: " + Arrays.toString(range)); + } + + Gauge g = r.determineGaugeByPosition(range[0]); + if (g == null) { + logger.warn("no gauge found for km: " + range[0]); + return null; + } + + if (debug) { + logger.debug("convert w->q with gauge '" + g.getName() + "'"); + } + + DischargeTable dt = g.fetchMasterDischargeTable(); + + if (dt == null) { + logger.warn("No master discharge table found for gauge '" + + g.getName() + "'"); + return null; + } + + double [][] values = DischargeTables.loadDischargeTableValues(dt, 1); + + TDoubleArrayList wsOut = new TDoubleArrayList(ws.length); + TDoubleArrayList qsOut = new TDoubleArrayList(ws.length); + + boolean generatedWs = false; + + for (int i = 0; i < ws.length; i++) { + if (Double.isNaN(ws[i])) { + logger.warn("W is NaN: ignored"); + continue; + } + double w = ws[i] / 100d; + double [] qs = DischargeTables.getQsForW(values, w); + + if (qs.length == 0) { + logger.warn("No Qs found for W = " + ws[i]); + } + else { + for (double q: qs) { + wsOut.add(ws[i]); + qsOut.add(q * 100d); + } + } + generatedWs |= qs.length != 1; + } + + return new double [][] { + qsOut.toNativeArray(), + generatedWs ? wsOut.toNativeArray() : null + }; + } + + + /** + * Determines the selected mode of distance/range input. + * + * @return true, if the range mode is selected otherwise false. + */ + public boolean isRange() { + StateData mode = getData("ld_mode"); + + if (mode == null) { + logger.warn("No mode location/range chosen. Defaults to range."); + return true; + } + + String value = (String) mode.getValue(); + + return value.equals("distance"); + } + + + /** + * Returns the selected distance based on a given range (from, to). + * + * @param dFrom The StateData that contains the lower value. + * @param dTo The StateData that contains the upper value. + * + * @return the selected distance. + */ + protected double[] getDistanceByRange(StateData dFrom, StateData dTo) { + double from = Double.parseDouble((String) dFrom.getValue()); + double to = Double.parseDouble((String) dTo.getValue()); + + return new double[] { from, to }; + } + + + /** + * Returns the selected Kms. + * + * @param distance An 2dim array with [lower, upper] values. + * + * @return the selected Kms. + */ + public double[] getKms(double[] distance) { + StateData dStep = getData("ld_step"); + + if (dStep == null) { + logger.warn("No step width given. Cannot compute Kms."); + return null; + } + + double step = Double.parseDouble((String) dStep.getValue()); + + // transform step from 'm' into 'km' + step = step / 1000; + + if (step == 0d) { + step = DEFAULT_KM_STEPS; + } + + return DoubleUtil.explode(distance[0], distance[1], step); + } + + + /** + * Returns the selected Kms. + * + * @return the selected kms. + */ + public double[] getKms() { + if (isRange()) { + double[] distance = FLYSUtils.getKmRange(this); + return getKms(distance); + + } + else { + return LocationDistanceSelect.getLocations(this); + } + } + + + public double [] getFromToStep() { + if (!isRange()) { + return null; + } + double [] fromTo = FLYSUtils.getKmRange(this); + + if (fromTo == null) { + return null; + } + + StateData dStep = getData("ld_step"); + if (dStep == null) { + return null; + } + + double [] result = new double[3]; + result[0] = fromTo[0]; + result[1] = fromTo[1]; + + try { + String step = (String)dStep.getValue(); + result[2] = DoubleUtil.round(Double.parseDouble(step) / 1000d); + } + catch (NumberFormatException nfe) { + return null; + } + + return result; + } + + + /** + * Returns the gauge based on the current distance and river. + * + * @return the gauge. + */ + public Gauge getGauge() { + return FLYSUtils.getGauge(this); + } + + + + + /** + * This method returns the Q values. + * + * @return the selected Q values or null, if no Q values are selected. + */ + public double[] getQs() { + StateData dMode = getData("wq_isq"); + StateData dSelection = getData("wq_isrange"); + + boolean isRange = dSelection != null + ? Boolean.valueOf((String)dSelection.getValue()) + : false; + + if (isQ()) { + if (!isRange) { + return getSingleWQValues(); + } + else { + return getWQTriple(); + } + } + else { + logger.warn("You try to get Qs, but W has been inserted."); + return null; + } + } + + + public boolean isQ() { + StateData mode = getData("wq_isq"); + String value = (mode != null) ? (String) mode.getValue() : null; + return value != null ? Boolean.valueOf(value) : false; + } + + public boolean isW() { + StateData mode = getData("wq_isq"); + String value = (mode != null) ? (String) mode.getValue() : null; + return value != null ? !Boolean.valueOf(value) : false; + } + + public boolean isFreeW() { + if(!isW()) { + return false; + } + StateData mode = getData("wq_isfree"); + String value = (mode != null) ? (String) mode.getValue() : null; + + return value != null ? Boolean.valueOf(value) : false; + } + + + /** + * Returns true, if the parameter is set to compute data on a free range. + * Otherwise it returns false, which tells the calculation that it is bound + * to a gauge. + * + * @return true, if the calculation should compute on a free range otherwise + * false and the calculation is bound to a gauge. + */ + public boolean isFreeQ() { + if(!isQ()) { + return false; + } + StateData mode = getData("wq_isfree"); + String value = (mode != null) ? (String) mode.getValue() : null; + + logger.debug("isFreeQ: " + value); + + return value != null && Boolean.valueOf(value); + } + + + /** + * Returns the Q values based on a specified kilometer range. + * + * @param range A 2dim array with lower and upper kilometer range. + * + * @return an array of Q values. + */ + public double[] getQs(double[] range) { + StateData dMode = getData("wq_isq"); + + if (isQ()) { + return getWQForDist(range); + } + + logger.warn("You try to get Qs, but Ws has been inserted."); + return null; + } + + + /** + * Returns the W values based on a specified kilometer range. + * + * @param range A 2dim array with lower and upper kilometer range. + * + * @return an array of W values. + */ + public double[] getWs(double[] range) { + if (isW()) { + return getWQForDist(range); + } + + logger.warn("You try to get Ws, but Qs has been inserted."); + return null; + } + + + /** + * This method returns the W values. + * + * @return the selected W values or null, if no W values are selected. + */ + public double[] getWs() { + StateData dSingle = getData("wq_single"); + + if (isW()) { + if (dSingle != null) { + return getSingleWQValues(); + } + else { + return getWQTriple(); + } + } + else { + logger.warn("You try to get Ws, but Q has been inserted."); + return null; + } + } + + /** + * This method returns the given W or Q values for a specific range + * (inserted in the WQ input panel for discharge longitudinal sections). + * + * @param dist A 2dim array with lower und upper kilometer values. + * + * @return an array of W or Q values. + */ + protected double[] getWQForDist(double[] dist) { + logger.debug("Search wq values for range: " + dist[0] + " - " + dist[1]); + StateData data = getData("wq_values"); + + if (data == null) { + logger.warn("Missing wq values!"); + return null; + } + + String dataString = (String) data.getValue(); + String[] ranges = dataString.split(":"); + + for (String range: ranges) { + String[] parts = range.split(";"); + + double lower = Double.parseDouble(parts[0]); + double upper = Double.parseDouble(parts[1]); + + if (lower <= dist[0] && upper >= dist[1]) { + String[] values = parts[2].split(","); + + int num = values.length; + double[] res = new double[num]; + + for (int i = 0; i < num; i++) { + try { + res[i] = Double.parseDouble(values[i]); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + return res; + } + } + + logger.warn("Specified range for WQ not found!"); + + return null; + } + + + /** + * This method returns an array of inserted WQ triples that consist of from, + * to and the step width. + * + * @return an array of from, to and step width. + */ + protected double[] getWQTriple() { + StateData dFrom = getData("wq_from"); + StateData dTo = getData("wq_to"); + + if (dFrom == null || dTo == null) { + logger.warn("Missing start or end value for range."); + return null; + } + + double from = Double.parseDouble((String) dFrom.getValue()); + double to = Double.parseDouble((String) dTo.getValue()); + + StateData dStep = getData("wq_step"); + + if (dStep == null) { + logger.warn("No step width given. Cannot compute Qs."); + return null; + } + + double step = Double.parseDouble((String) dStep.getValue()); + + // if no width is given, the DEFAULT_Q_STEPS is used to compute the step + // width. Maybe, we should round the value to a number of digits. + if (step == 0d) { + double diff = to - from; + step = diff / DEFAULT_Q_STEPS; + } + + return DoubleUtil.explode(from, to, step); + } + + + /** + * Returns an array of inserted WQ double values stored as whitespace + * separated list. + * + * @return an array of W or Q values. + */ + protected double[] getSingleWQValues() { + StateData dSingle = getData("wq_single"); + + if (dSingle == null) { + logger.warn("Cannot determine single WQ values. No data given."); + return null; + } + + String tmp = (String) dSingle.getValue(); + String[] strValues = tmp.split(" "); + + TDoubleArrayList values = new TDoubleArrayList(); + + for (String strValue: strValues) { + try { + values.add(Double.parseDouble(strValue)); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + values.sort(); + + return values.toNativeArray(); + } + + /** + * Returns the WstValueTable of current river. + */ + public WstValueTable getWstValueTable() { + River r = FLYSUtils.getRiver(this); + return WstValueTableFactory.getTable(r); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSBackgroundArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,48 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.states.DefaultState; + + +public class WMSBackgroundArtifact extends StaticFLYSArtifact { + + public static final String NAME = "wmsbackground"; + + private static final Logger logger = + Logger.getLogger(WMSBackgroundArtifact.class); + + + @Override + public String getName() { + return NAME; + } + + + @Override + protected void initialize(Artifact artifact, Object context, CallMeta meta) { + logger.debug("Initialize internal state with: "+ artifact.identifier()); + + FLYSArtifact flys = (FLYSArtifact) artifact; + addData("river", flys.getData("river")); + + List<Facet> fs = new ArrayList<Facet>(); + + // TODO Add CallMeta + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + + if (!fs.isEmpty()) { + facets.put(getCurrentStateId(), fs); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,150 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Building; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSBuildingsArtifact extends WMSDBArtifact { + + public static final String NAME = "buildings"; + + + private static final Logger logger = + Logger.getLogger(WMSBuildingsArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSBuildingsArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new BuildingsState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class BuildingsState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(BuildingsState.class); + + protected int riverId; + + public BuildingsState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + @Override + protected String getFacetType() { + return FLOODMAP_BUILDINGS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Building> buildings = + Building.getBuildings(getRiverId(), getName()); + + Envelope max = null; + + for (Building b: buildings) { + Envelope env = b.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM buildings USING SRID " + srid; + } + else { + return "geom FROM buildings USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,166 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.Catchment; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSCatchmentArtifact extends WMSDBArtifact { + + public static final String NAME = "catchment"; + + + private static final Logger logger = + Logger.getLogger(WMSCatchmentArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSCatchmentArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new CatchmentState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class CatchmentState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(CatchmentState.class); + + protected int riverId; + + public CatchmentState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + String[] parts = ids.split(";"); + + try { + riverId = Integer.parseInt(parts[0]); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + ids + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_CATCHMENT; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Catchment> catchments = + Catchment.getCatchments(getRiverId(), getName()); + + Envelope max = null; + + for (Catchment c: catchments) { + Envelope env = c.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM catchment USING SRID " + srid; + } + else { + return "geom FROM catchment USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "POLYGON"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,329 @@ +package de.intevation.flys.artifacts; + +import java.io.File; + +import java.util.ArrayList; +import java.util.List; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import org.hibernate.impl.SessionFactoryImpl; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.FileTools; + +import de.intevation.artifactdatabase.data.DefaultStateData; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + + +import de.intevation.flys.backend.SessionFactoryProvider; + +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.MapfileGenerator; + + +public abstract class WMSDBArtifact extends StaticFLYSArtifact { + + private static final Logger logger = Logger.getLogger(WMSDBArtifact.class); + + public static final Pattern DB_URL_PATTERN = + Pattern.compile("(.*)\\/\\/(.*):([0-9]+)\\/([a-zA-Z]+)"); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSDBArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + + String ids = getDatacageIDValue(data); + + if (ids != null && ids.length() > 0) { + addData("ids", new DefaultStateData("ids", null, null, ids)); + } + else { + throw new IllegalArgumentException("No attribute 'ids' found!"); + } + + List<Facet> fs = new ArrayList<Facet>(); + + WMSDBState state = (WMSDBState) getCurrentState(context); + state.computeInit(this, hash(), context, callMeta, fs); + + if (!fs.isEmpty()) { + facets.put(getCurrentStateId(), fs); + } + } + + + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta callMeta) + { + // do nothing + } + + + @Override + protected State getState(Object context, String stateID) { + return getCurrentState(context); + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getCurrentState(context)); + + return states; + } + + + + public static abstract class WMSDBState extends DefaultState { + private static final Logger logger = Logger.getLogger(WMSDBState.class); + + protected FLYSArtifact artifact; + + protected String name; + protected int riverId; + + + public WMSDBState() {} + + public WMSDBState(FLYSArtifact artifact) { + this.artifact = artifact; + this.name = null; + this.riverId = 0; + } + + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("WMSDBState.computeInit"); + + String type = getFacetType(); + + WMSDBLayerFacet facet = new WMSDBLayerFacet( + 0, + type, + getTitle(meta), + ComputeType.INIT, + getID(), hash, + getUrl()); + + String name = type + "-" + artifact.identifier(); + + facet.addLayer(name); + facet.setExtent(getExtent()); + facet.setSrid(getSrid()); + facet.setData(getDataString()); + facet.setFilter(getFilter()); + facet.setGeometryType(getGeometryType()); + facet.setConnection(getConnection()); + facet.setConnectionType(getConnectionType()); + facet.setLabelItem(getLabelItem()); + + facets.add(facet); + + return null; + } + + /** + * This method returns a connection string for databases used by + * Mapserver's Mapfile. + * + * @return A connection string for Mapserver. + */ + protected String getConnection() { + SessionFactoryImpl sf = (SessionFactoryImpl) + SessionFactoryProvider.getSessionFactory(); + + String user = SessionFactoryProvider.getUser(sf); + String pass = SessionFactoryProvider.getPass(sf); + String url = SessionFactoryProvider.getURL(sf); + + logger.debug("Parse connection url: " + url); + + Matcher m = DB_URL_PATTERN.matcher(url); + if (!m.matches()) { + logger.warn("Could not parse Connection string."); + return null; + } + + logger.debug("Groups for connection string: " + m.groupCount()); + int groups = m.groupCount(); + + for (int i = 0; i <= groups; i++) { + logger.debug("Group " + i + ": " + m.group(i)); + } + + String connection = null; + + if (FLYSUtils.isUsingOracle()) { + if (groups < 3) { + logger.warn("Could only partially parse connection string."); + return null; + } + + String host = m.group(2); + String port = m.group(3); + + connection = user + "/" + pass + "@" + host; + } + else { + if (groups < 4) { + logger.warn("Could only partially parse connection string."); + return null; + } + + String host = m.group(2); + String port = m.group(3); + String db = m.group(4); + + StringBuilder sb = new StringBuilder(); + sb.append("dbname=" + db); + sb.append("host='" + host + "'"); + sb.append("port=" + port); + sb.append("password='" + pass + "'"); + sb.append("sslmode=disable"); + + connection = sb.toString(); + } + + logger.debug("Created connection: '" + connection + "'"); + + return connection; + } + + protected String getConnectionType() { + return FLYSUtils.isUsingOracle() ? "oraclespatial" : "postgis"; + } + + protected String getLabelItem() { + return null; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + String[] parts = ids.split(";"); + + try { + riverId = Integer.parseInt(parts[0]); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + parts[0] + "'"); + } + } + + return riverId; + } + + /** + * Returns the name of the WMS layer. This method extracts the name + * from 'ids' data string. It is expected, that the 'ids' string is + * seperated by ';' and that the name is placed at index 1. + * + * @return the name of the WMS layer. + */ + public String getName() { + if (name == null) { + String ids = artifact.getDataAsString("ids"); + + String parts[] = ids != null ? ids.split(";") : null; + + if (parts != null && parts.length >= 2) { + name = parts[1]; + } + } + + return name; + } + + + /** + * Returns the name of the layer (returned by getName()) or the layer + * type if the name is empty. The layer type is created by an i18n + * string of getFacetType(). + * + * @param meta A CallMeta used for i18n. + * + * @return the name of the layer or its type if name is empty. + */ + protected String getTitle(CallMeta meta) { + String name = getName(); + + return name != null && name.length() > 0 + ? name + : Resources.getMsg( + meta, + getFacetType(), + getFacetType()); + } + + + @Override + public void endOfLife(Artifact owner, Object context) { + logger.info("Destroy WMSDBState: " + getID()); + + String p = FLYSUtils.getXPathString(FLYSUtils.XPATH_SHAPEFILE_DIR); + File dir = new File(p, owner.identifier()); + + if (dir != null && dir.exists()) { + logger.debug("Try to delete directory '" + dir + "'"); + + FileTools.deleteRecursive(dir); + MapfileGenerator.getInstance().update(); + } + } + + + protected abstract String getFacetType(); + + protected abstract String getUrl(); + + protected abstract String getSrid(); + + protected abstract Envelope getExtent(); + + protected abstract String getFilter(); + + protected abstract String getDataString(); + + protected abstract String getGeometryType(); + } // end of WMSDBState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,148 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Fixpoint; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSFixpointsArtifact extends WMSDBArtifact { + + public static final String NAME = "fixpoints"; + + + private static final Logger logger = + Logger.getLogger(WMSFixpointsArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSFixpointsArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new FixpointsState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class FixpointsState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(FixpointsState.class); + + protected int riverId; + + public FixpointsState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + @Override + protected String getFacetType() { + return FLOODMAP_FIXPOINTS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Fixpoint> fixpoints = Fixpoint.getFixpoints(getRiverId()); + + Envelope max = null; + + for (Fixpoint f: fixpoints) { + Envelope env = f.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()); + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM fixpoints USING SRID " + srid; + } + else { + return "geom FROM fixpoints USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "POINT"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,150 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Floodmaps; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSFloodmapsArtifact extends WMSDBArtifact { + + public static final String NAME = "floodmaps"; + + + private static final Logger logger = + Logger.getLogger(WMSFloodmapsArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSFloodmapsArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new FloodmapsState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class FloodmapsState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(FloodmapsState.class); + + protected int riverId; + + public FloodmapsState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + @Override + protected String getFacetType() { + return FLOODMAP_FLOODMAPS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Floodmaps> floodmaps = + Floodmaps.getFloodmaps(getRiverId(), getName()); + + Envelope max = null; + + for (Floodmaps f: floodmaps) { + Envelope env = f.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM floodmaps USING SRID " + srid; + } + else { + return "geom FROM floodmaps USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "POLYGON"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,155 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.Floodplain; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSFloodplainArtifact extends WMSDBArtifact { + + public static final String NAME = "floodplain"; + + + private static final Logger logger = + Logger.getLogger(WMSFloodplainArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSFloodplainArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new FloodplainState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class FloodplainState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(FloodplainState.class); + + protected int riverId; + + public FloodplainState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + + try { + riverId = Integer.parseInt(ids); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + ids + "'"); + } + } + + return riverId; + } + + protected River getRiver() { + return RiverFactory.getRiver(getRiverId()); + } + + @Override + protected String getFacetType() { + return FLOODMAP_FLOODPLAIN; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = getRiver(); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + River river = getRiver(); + Floodplain plain = Floodplain.getFloodplain(river.getName()); + + return GeometryUtils.transform( + plain.getGeom().getEnvelopeInternal(), + getSrid()); + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()); + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM floodplain USING SRID " + srid; + } + else { + return "geom FROM floodplain USING UNIQUE id USING SRID " +srid; + } + } + + @Override + protected String getGeometryType() { + return "POLYGON"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,153 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.GaugeLocation; + +import de.intevation.flys.artifacts.WMSDBArtifact.WMSDBState; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSGaugeLocationArtifact extends WMSDBArtifact { + + public static final String NAME = "wmsgaugelocation"; + + + private static final Logger logger = + Logger.getLogger(WMSGaugeLocationArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSGaugeLocationArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new WMSGaugeLocationState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + + public static class WMSGaugeLocationState extends WMSDBState implements FacetTypes { + + private static final Logger logger = + Logger.getLogger(WMSGaugeLocationState.class); + + protected Geometry geom; + + public WMSGaugeLocationState(WMSDBArtifact artifact) { + super(artifact); + } + + @Override + protected String getFacetType() { + return FLOODMAP_GAUGE_LOCATION; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<GaugeLocation> gauges = + GaugeLocation.getGaugeLocations(getRiverId(), getName()); + + Envelope max = null; + + for (GaugeLocation gauge: gauges) { + Envelope env = gauge.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " and name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM gauge_location USING SRID " + srid; + } + else { + return "geom FROM gauge_location " + + "USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "POINT"; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,165 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Hws; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSHwsArtifact extends WMSDBArtifact { + + public static final String NAME = "hws"; + + + private static final Logger logger = + Logger.getLogger(WMSHwsArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSHwsArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new HwsState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class HwsState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(HwsState.class); + + protected int riverId; + + public HwsState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + String[] parts = ids.split(";"); + + try { + riverId = Integer.parseInt(parts[0]); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + parts[0] + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_HWS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Hws> hws = Hws.getHws(getRiverId(), getName()); + + Envelope max = null; + + for (Hws h: hws) { + Envelope env = h.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM hws USING SRID " + srid; + } + else { + return "geom FROM hws USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,150 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.HydrBoundary; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSHydrBoundaryArtifact extends WMSDBArtifact { + + public static final String NAME = "hydr_boundary"; + + + private static final Logger logger = + Logger.getLogger(WMSHydrBoundaryArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSHydrBoundaryArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new HydrBoundaryState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class HydrBoundaryState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(HydrBoundaryState.class); + + protected int riverId; + + public HydrBoundaryState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + @Override + protected String getFacetType() { + return FLOODMAP_HYDR_BOUNDARY; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<HydrBoundary> boundaries = HydrBoundary.getHydrBoundaries( + getRiverId(), getName()); + + Envelope max = null; + + for (HydrBoundary b: boundaries) { + Envelope env = b.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM hydr_boundaries USING SRID " + srid; + } + else { + return "geom FROM hydr_boundaries USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of HydrBoundaryState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,150 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.HydrBoundaryPoly; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSHydrBoundaryPolyArtifact extends WMSDBArtifact { + + public static final String NAME = "hydr_boundary_poly"; + + + private static final Logger logger = + Logger.getLogger(WMSHydrBoundaryPolyArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSHydrBoundaryArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new HydrBoundaryPolyState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class HydrBoundaryPolyState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(HydrBoundaryPolyState.class); + + protected int riverId; + + public HydrBoundaryPolyState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + @Override + protected String getFacetType() { + return FLOODMAP_HYDR_BOUNDARY_POLY; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<HydrBoundaryPoly> boundaries = HydrBoundaryPoly.getHydrBoundaries( + getRiverId(), getName()); + + Envelope max = null; + + for (HydrBoundaryPoly b: boundaries) { + Envelope env = b.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM hydr_boundaries USING SRID " + srid; + } + else { + return "geom FROM hydr_boundaries USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "POLYGON"; + } + } // end of HydrBoundaryState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,171 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.RiverAxisKm; + +import de.intevation.flys.artifacts.WMSDBArtifact.WMSDBState; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSKmArtifact extends WMSDBArtifact { + + public static final String NAME = "wmskm"; + + + private static final Logger logger = Logger.getLogger(WMSKmArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSKmArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new WMSKmState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + + public static class WMSKmState extends WMSDBState implements FacetTypes { + + private static final Logger logger = Logger.getLogger(WMSKmState.class); + + protected Geometry geom; + protected int riverId; + + public WMSKmState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + + try { + riverId = Integer.parseInt(ids); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + ids + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_KMS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<RiverAxisKm> kms = RiverAxisKm.getRiverAxisKms(getRiverId()); + + Envelope max = null; + + for (RiverAxisKm km: kms) { + Envelope env = km.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()); + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM river_axes_km USING SRID " + srid; + } + else { + return "geom FROM river_axes_km " + + "USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getLabelItem() { + return "km"; + } + + @Override + protected String getGeometryType() { + return "POINT"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,165 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Line; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSLineArtifact extends WMSDBArtifact { + + public static final String NAME = "lines"; + + + private static final Logger logger = + Logger.getLogger(WMSLineArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSLineArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new LineState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class LineState extends WMSDBState implements FacetTypes + { + private static final Logger logger = + Logger.getLogger(LineState.class); + + protected int riverId; + + public LineState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + String[] parts = ids.split(";"); + + try { + riverId = Integer.parseInt(parts[0]); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + parts[0] + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_LINES; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + List<Line> lines = Line.getLines(getRiverId(), getName()); + + Envelope max = null; + + for (Line l: lines) { + Envelope env = l.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()) + + " AND name='" + getName() + "'"; + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM lines USING SRID " + srid; + } + else { + return "geom FROM lines USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of WMSKmState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,167 @@ +package de.intevation.flys.artifacts; + +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.CrossSectionTrack; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; + + +public class WMSQPSArtifact extends WMSDBArtifact { + + public static final String NAME = "qps"; + + + private static final Logger logger = + Logger.getLogger(WMSQPSArtifact.class); + + + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WMSQPSArtifact.setup"); + + super.setup(identifier, factory, context, callMeta, data); + } + + + @Override + public String getName() { + return NAME; + } + + + @Override + public State getCurrentState(Object cc) { + State s = new WMSQPSState(this); + + List<Facet> fs = facets.get(getCurrentStateId()); + + DefaultOutput o = new DefaultOutput( + "floodmap", + "floodmap", + "image/png", + fs, + "map"); + + s.getOutputs().add(o); + + return s; + } + + + public static class WMSQPSState extends WMSDBState implements FacetTypes { + + private static final Logger logger = + Logger.getLogger(WMSQPSState.class); + + protected int riverId; + + public WMSQPSState(WMSDBArtifact artifact) { + super(artifact); + riverId = 0; + } + + public int getRiverId() { + if (riverId == 0) { + String ids = artifact.getDataAsString("ids"); + + try { + riverId = Integer.parseInt(ids); + } + catch (NumberFormatException nfe) { + logger.error("Cannot parse river id from '" + ids + "'"); + } + } + + return riverId; + } + + @Override + protected String getFacetType() { + return FLOODMAP_QPS; + } + + @Override + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + @Override + protected String getSrid() { + River river = RiverFactory.getRiver(getRiverId()); + return FLYSUtils.getRiverSrid(river.getName()); + } + + @Override + protected Envelope getExtent() { + River river = RiverFactory.getRiver(getRiverId()); + + List<CrossSectionTrack> qps = + CrossSectionTrack.getCrossSectionTrack(river.getName()); + + Envelope max = null; + + for (CrossSectionTrack qp: qps) { + Envelope env = qp.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + continue; + } + + max.expandToInclude(env); + } + + return max != null + ? GeometryUtils.transform(max, getSrid()) + : max; + } + + @Override + protected String getFilter() { + return "river_id=" + String.valueOf(getRiverId()); + } + + @Override + protected String getDataString() { + String srid = getSrid(); + + if (FLYSUtils.isUsingOracle()) { + return "geom FROM cross_section_tracks USING SRID " + srid; + } + else { + return "geom FROM cross_section_tracks " + + "USING UNIQUE id USING SRID " + srid; + } + } + + @Override + protected String getGeometryType() { + return "LINE"; + } + } // end of WMSQPSState +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,295 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WQFacet; +import de.intevation.flys.artifacts.model.WKmsFactory; +import de.intevation.flys.artifacts.model.WQKmsFactory; +import de.intevation.flys.artifacts.model.WstValueTable; +import de.intevation.flys.artifacts.model.WstValueTableFactory; + +import de.intevation.flys.artifacts.states.StaticState; +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * Artifact to access additional "waterlevel/discharge"-type of data, like + * fixation measurements, but doing so with costy interpolation. + * + * This artifact neglects (Static)FLYSArtifacts capabilities of interaction + * with the StateEngine by overriding the getState*-methods. + */ +public class WQKmsInterpolArtifact +extends StaticFLYSArtifact +implements FacetTypes +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(WQKmsInterpolArtifact.class); + + /** State name. */ + public static final String STATIC_STATE_NAME = + "state.additional_wqkms.interpol.static"; + + /** Artifact name. */ + private static final String NAME = "staticwqkmsinterpol"; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(NAME, FacetActivity.INACTIVE); + } + + /** One and only state to be in. */ + protected transient State state = null; + + + /** + * Trivial Constructor. + */ + public WQKmsInterpolArtifact() { + logger.debug("WQKmsInterpolArtifact.WQKmsInterpolArtifact"); + } + + + /** Return fixed artifact (types) name. */ + @Override + public String getName() { + return NAME; + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("WQKmsInterpolArtifact.setup"); + + state = new StaticState(STATIC_STATE_NAME); + + List<Facet> fs = new ArrayList<Facet>(); + String code = getDatacageIDValue(data); + + // TODO Go for JSON, one day. + //ex.: flood_protection-wstv-114-12 + if (code != null) { + String [] parts = code.split("-"); + + logger.debug("WQKmsInterpolArtifact.setup: code " + code); + + if (parts.length >= 4) { + int wst = Integer.parseInt(parts[3]); + int col = -1; + String colpos = parts[2]; + // Are we interested in a single column or in all columns? + if (colpos.equals("A")) { + ; // Take all. + } + else { + col = Integer.parseInt(colpos); + addStringData("col_pos", parts[2]); + } + addStringData("wst_id", parts[3]); + String wkmsName = (col >= 0) + ? WKmsFactory.getWKmsName(col, wst) + : WKmsFactory.getWKmsName(wst); + String name; + if (parts[0].startsWith("height")){ + name = STATIC_WQ_ANNOTATIONS; + } + else if (parts[0].startsWith("flood")) { + name = STATIC_WKMS_INTERPOL; + } + else { + name = STATIC_WQ; + } + + Facet wQFacet = new WQFacet(name, + Resources.getMsg( + callMeta, + wkmsName, + wkmsName)); + fs.add(wQFacet); + facets.put(state.getID(), fs); + } + } + else { + logger.warn("WQKmsInterpolArtifact: no code"); + } + + spawnState(); + super.setup(identifier, factory, context, callMeta, data); + } + + + /** + * Initialize the static state with output. + * @return static state + */ + protected State spawnState() { + state = new StaticState(STATIC_STATE_NAME); + List<Facet> fs = facets.get(STATIC_STATE_NAME); + DefaultOutput output = new DefaultOutput( + "general", + "general", + "image/png", + fs, + "chart"); + + state.getOutputs().add(output); + + return state; + } + + + /** + * Called via setup. + * + * @param artifact The master-artifact. + */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + logger.debug("WQKmsInterpolArtifact.initialize"); + FLYSArtifact winfo = (FLYSArtifact) artifact; + importData(winfo, "river"); + importData(winfo, "ld_locations"); + } + + + /** + * Get a list containing the one and only State. + * @param context ignored. + * @return list with one and only state. + */ + @Override + protected List<State> getStates(Object context) { + ArrayList<State> states = new ArrayList<State>(); + states.add(getState()); + return states; + } + + + /** + * Get WQ at a given km. + * @param currentKm the requested km. If NULL, ld_location data + * will be used. + */ + public double [][] getWQAtKm(Double currentKm) { + + WstValueTable interpolator = null; + // Get WstValueTable + if (getDataAsString("col_pos") != null) { + interpolator = WstValueTableFactory.getWstColumnTable( + getDataAsInt("wst_id"), getDataAsInt("col_pos")); + } + else { + interpolator = WstValueTableFactory.getTable( + getDataAsInt("wst_id")); + } + + Double tmp = (currentKm != null) + ? currentKm + : getDataAsDouble("ld_locations"); + + double [][] vs = interpolator.interpolateWQColumnwise( + tmp != null ? tmp : 0); + + for (int x = 0; x < vs[1].length; x++) { + logger.debug("getWQAtKm: Q/W " + vs[0][x] + " / " + vs[1][x]); + } + + return vs; + } + + + /** + * Get a DataItem casted to int (0 if fails). + */ + public int getDataAsInt(String dataName) { + String val = getDataAsString(dataName); + try { + return Integer.parseInt(val); + } + catch (NumberFormatException e) { + logger.warn("Could not get data " + dataName + " as int", e); + return 0; + } + } + + + /** + * Get the "current" state (there is but one). + * @param cc ignored. + * @return the "current" (only possible) state. + */ + @Override + public State getCurrentState(Object cc) { + return getState(); + } + + + /** + * Get the only possible state. + * @return the state. + */ + protected State getState() { + return getState(null, null); + } + + + /** + * Get the state. + * @param context ignored. + * @param stateID ignored. + * @return the state. + */ + @Override + protected State getState(Object context, String stateID) { + return (state != null) + ? state + : spawnState(); + } + + + /** + * Get WQKms from factory. + * @param idx param is not needed (TODO) + * @return WQKms according to parameterization (can be null); + */ + public WQKms getWQKms(int idx) { + logger.debug("WQKmsInterpolArtifact.getWQKms"); + logger.warn("Stub, getWQKms not yet implemented."); + + return WQKmsFactory.getWQKms( + Integer.parseInt(getDataAsString("col_pos")), + Integer.parseInt(getDataAsString("wst_id"))); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,14 @@ +package de.intevation.flys.artifacts; + +import de.intevation.flys.artifacts.geom.Lines; +import de.intevation.flys.model.FastCrossSectionLine; +/** + * Interface, Artifact can create WaterLines (Water against Cross-Profile). + */ +public interface WaterLineArtifact { + + /** Get points that define a line of a (water)facet against a cross- + * section. */ + public Lines.LineData getWaterLines(int facetIdx, FastCrossSectionLine csl, double d, double w); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,117 @@ +package de.intevation.flys.artifacts; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.states.DefaultState; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + + +/** + * Clone of an WINFOArtifact to expose exactly one waterlevel only. + * All Facets of the "longitudinal_section" output will be added to the + * "w_differences" output and filterFacets adjusted accordingly. + * + * @TODO Straighten inheritance-line (waterlevel-WINFO or vice versa). + */ +public class WaterlevelArtifact extends WINFOArtifact { + + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(WaterlevelArtifact.class); + + /** The name of the artifact. */ + public static final String ARTIFACT_NAME = "waterlevel"; + + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(ARTIFACT_NAME, FacetActivity.INACTIVE); + } + + /** + * The default constructor. + */ + public WaterlevelArtifact() { + } + + + /** + * Setup and restate longitudinal_section filterfacets to apply to the + * w_differences output, too. Also, for w_differences, add respective q- + * filter facets. + */ + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + super.setup(identifier, factory, context, callMeta, data); + // For w_differences, also allow q-facets. + if(filterFacets != null) { + List<Facet> list = new ArrayList<Facet>(); + List<Facet> wlist = filterFacets.get("longitudinal_section"); + for (Facet f: wlist) { + if (!f.getName().equals("longitudinal_section.q")) { + DefaultFacet df = new DefaultFacet(f.getIndex(), + "longitudinal_section.q", ""); + list.add(df); + } + } + + list.addAll(wlist); + + filterFacets.put("w_differences", list); + } + } + + + /** + * Clone important stuff of an WINFOArtifact. + * @param artifact the WINFOArtifact to clone stuff from. + */ + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + WINFOArtifact winfo = (WINFOArtifact) artifact; + this.data = winfo.cloneData(); + logger.debug("Cloned data of winfo artifact."); + // Statically add Facets. + List<Facet> fs = new ArrayList<Facet>(); + DefaultState state = (DefaultState) getCurrentState(context); + state.computeInit(this, hash(), context, meta, fs); + if (!fs.isEmpty()) { + logger.debug("Facets to add in WaterlevelArtifact.initialize ."); + facets.put(getCurrentStateId(), fs); + } + else { + logger.debug("No facets to add in WaterlevelArtifact.initialize (" + + state.getID() + ")."); + } + } + + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + public String getName() { + return ARTIFACT_NAME; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/Access.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,174 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.DateRange; + +import de.intevation.flys.utils.FLYSUtils; + +import gnu.trove.TDoubleArrayList; + +import java.util.ArrayList; +import java.util.Date; + +import org.apache.log4j.Logger; + +public class Access +{ + private static Logger log = Logger.getLogger(Access.class); + + protected FLYSArtifact artifact; + + public Access() { + } + + public Access(FLYSArtifact artifact) { + this.artifact = artifact; + } + + public FLYSArtifact getArtifact() { + return artifact; + } + + public void setArtifact(FLYSArtifact artifact) { + this.artifact = artifact; + } + + protected String getString(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "' value"); + return null; + } + return (String)sd.getValue(); + } + + protected Double getDouble(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "' value"); + return null; + } + try { + return Double.valueOf((String)sd.getValue()); + } + catch (NumberFormatException nfe) { + log.warn(key + " '" + sd.getValue() + "' is not numeric."); + } + return null; + } + + protected Long getLong(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "' value"); + return null; + } + try { + return Long.valueOf((String)sd.getValue()); + } + catch (NumberFormatException nfe) { + log.warn(key + " '" + sd.getValue() + "' is not a long integer."); + } + return null; + } + + protected Integer getInteger(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "' value"); + return null; + } + try { + return Integer.valueOf((String)sd.getValue()); + } + catch (NumberFormatException nfe) { + log.warn(key + " '" + sd.getValue() + "' is not a integer."); + } + return null; + } + + protected int [] getIntArray(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key +"' value"); + return null; + } + return FLYSUtils.intArrayFromString((String)sd.getValue()); + } + + protected DateRange [] getDateRange(String key) { + + StateData sd = artifact.getData(key); + + if (sd == null) { + log.warn("missing '" + key + "'"); + return null; + } + + String data = (String)sd.getValue(); + String[] pairs = data.split("\\s*;\\s*"); + + ArrayList<DateRange> aPs = new ArrayList<DateRange>(pairs.length); + + for (int i = 0; i < pairs.length; i++) { + String[] fromTo = pairs[i].split("\\s*,\\s*"); + if (fromTo.length >= 2) { + try { + Date from = new Date(Long.parseLong(fromTo[0])); + Date to = new Date(Long.parseLong(fromTo[1])); + DateRange aP = new DateRange(from, to); + if (!aPs.contains(aP)) { + aPs.add(aP); + } + } + catch (NumberFormatException nfe) { + log.warn(key + " contains no long values.", nfe); + } + } + } + + DateRange [] result = aPs.toArray(new DateRange[aPs.size()]); + + if (log.isDebugEnabled()) { + for (int i = 0; i < result.length; ++i) { + DateRange ap = result[i]; + log.debug("period " + + ap.getFrom() + " - " + ap.getTo()); + } + } + + return result; + } + + protected Boolean getBoolean(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "' value"); + return null; + } + return Boolean.valueOf((String)sd.getValue()); + } + + protected double [] getDoubleArray(String key) { + StateData sd = artifact.getData(key); + if (sd == null) { + log.warn("missing '" + key + "'"); + return null; + } + String [] parts = ((String)sd.getValue()).split("[\\s;]+"); + TDoubleArrayList list = new TDoubleArrayList(parts.length); + for (String part: parts) { + try { + list.add(Double.parseDouble(part)); + } + catch (NumberFormatException nfe) { + log.warn("'" + part + "' is not numeric."); + } + } + return list.toNativeArray(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,119 @@ +package de.intevation.flys.artifacts.access; + +import gnu.trove.TIntArrayList; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.states.SoundingsSelect; + + +public class BedHeightAccess extends Access { + + private static final Logger logger = Logger.getLogger(BedHeightAccess.class); + + private int[] singleIDs; + private int[] epochIDs; + + private Double lowerKM; + private Double upperKM; + + private String time; + + public BedHeightAccess(FLYSArtifact artifact) { + super(artifact); + } + + + public Double getLowerKM() { + if (lowerKM == null) { + lowerKM = getDouble("ld_from"); + } + + return lowerKM; + } + + + public Double getUpperKM() { + if (upperKM == null) { + upperKM = getDouble("ld_to"); + } + + return upperKM; + } + + + public int[] getBedHeightSingleIDs() { + if (singleIDs == null) { + String data = getString("soundings"); + + if (data == null) { + logger.warn("No 'soundings' parameter specified!"); + return null; + } + + String[] parts = data.split(";"); + + TIntArrayList ids = new TIntArrayList(); + + for (String part: parts) { + if (part.indexOf(SoundingsSelect.PREFIX_SINGLE) >= 0) { + String tmp = part.replace(SoundingsSelect.PREFIX_SINGLE, ""); + + try { + ids.add(Integer.parseInt(tmp)); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse int from string: '" + tmp + "'"); + } + } + } + + singleIDs = ids.toNativeArray(); + } + + return singleIDs; + } + + + public String getYearEpoch() { + if (time == null) { + time = getString("ye_select"); + } + return time; + } + + + public int[] getBedHeightEpochIDs() { + if (epochIDs == null) { + String data = getString("soundings"); + + if (data == null) { + logger.warn("No 'soundings' parameter specified!"); + return null; + } + + String[] parts = data.split(";"); + + TIntArrayList ids = new TIntArrayList(); + + for (String part: parts) { + if (part.indexOf(SoundingsSelect.PREFIX_EPOCH) >= 0) { + String tmp = part.replace(SoundingsSelect.PREFIX_EPOCH, ""); + + try { + ids.add(Integer.parseInt(tmp)); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse int from string: '" + tmp + "'"); + } + } + } + + epochIDs = ids.toNativeArray(); + } + + return epochIDs; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.flys.artifacts.access; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.DateRange; + + +public class BedQualityAccess extends RiverAccess { + + private static final Logger logger = Logger + .getLogger(BedQualityAccess.class); + + private Double from; + private Double to; + private List<String> bedDiameter; + private List<String> bedloadDiameter; + private List<DateRange> ranges; + + public BedQualityAccess(FLYSArtifact artifact) { + super(artifact); + } + + public double getFrom() { + if (from == null) { + from = getDouble("ld_from"); + } + return from.doubleValue(); + } + + public double getTo() { + if (to == null) { + to = getDouble("ld_to"); + } + return to.doubleValue(); + } + + public List<DateRange> getDateRanges() { + if (ranges == null) { + ranges = extractRanges(getString("periods")); + } + return ranges; + } + + public List<String> getBedDiameter() { + String value = getString("bed_diameter"); + if (bedDiameter == null && value != null) { + bedDiameter = extractDiameter(value); + } + return bedDiameter; + } + + public List<String> getBedloadDiameter() { + String value = getString("load_diameter"); + if (bedloadDiameter == null && value != null) { + bedloadDiameter = extractDiameter(value); + } + return bedloadDiameter; + } + + private List<DateRange> extractRanges(String dateString) { + List<DateRange> list = new LinkedList<DateRange>(); + String[] dates = dateString.split(";"); + for (String s : dates) { + String[] pair = s.split(","); + try { + long l1 = Long.parseLong(pair[0]); + long l2 = Long.parseLong(pair[1]); + Date first = new Date(l1); + Date second = new Date(l2); + DateRange dr = new DateRange(first, second); + list.add(dr); + } + catch (NumberFormatException nfe) { + continue; + } + } + return list; + } + + private List<String> extractDiameter(String value) { + List<String> result = new LinkedList<String>(); + String[] diameter = value.split(";"); + for (String v : diameter) { + logger.debug("diameter: " + v); + String[] parts = v.split("\\."); + result.add(parts[parts.length - 1]); + logger.debug(parts[parts.length-1]); + } + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,126 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.RangeWithValues; + +import de.intevation.flys.utils.DoubleUtil; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class ExtremeAccess +extends RiverAccess +{ + private static Logger log = Logger.getLogger(ExtremeAccess.class); + + protected Double from; + protected Double to; + protected Double step; + + protected Long start; + protected Long end; + + protected Double percent; + + protected String function; + + protected List<RangeWithValues> ranges; + + public ExtremeAccess() { + } + + public ExtremeAccess(FLYSArtifact artifact) { + super(artifact); + } + + public Double getFrom() { + + if (from == null) { + from = getDouble("ld_from"); + } + + if (log.isDebugEnabled()) { + log.debug("from: '" + from + "'"); + } + + return from; + } + + public Double getTo() { + + if (to == null) { + to = getDouble("ld_to"); + } + + if (log.isDebugEnabled()) { + log.debug("to: '" + to + "'"); + } + + return to; + } + + public Double getStep() { + + if (step == null) { + step = getDouble("ld_step"); + } + + if (log.isDebugEnabled()) { + log.debug("step: '" + step + "'"); + } + + return step; + } + + public Double getPercent() { + + if (percent == null) { + percent = getDouble("percent"); + } + + if (log.isDebugEnabled()) { + log.debug("percent: '" + percent + "'"); + } + + return percent; + } + + public String getFunction() { + if (function == null) { + function = getString("function"); + } + + if (log.isDebugEnabled()) { + log.debug("function: '" + function + "'"); + } + + return function; + } + + public List<RangeWithValues> getRanges() { + + if (ranges == null) { + String rangesS = getString("ranges"); + if (ranges == null) { + return null; + } + ranges = new ArrayList<RangeWithValues>(); + DoubleUtil.parseSegments(rangesS, new DoubleUtil.SegmentCallback() { + @Override + public void newSegment(double from, double to, double [] values) { + ranges.add(new RangeWithValues(from, to, values)); + } + }); + } + + if (log.isDebugEnabled()) { + log.debug("ranges: " + ranges); + } + + return ranges; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/FixAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,158 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import java.util.Arrays; + +import org.apache.log4j.Logger; + +public class FixAccess +extends RiverAccess +{ + private static Logger log = Logger.getLogger(FixAccess.class); + + protected Double from; + protected Double to; + protected Double step; + + protected Long start; + protected Long end; + + protected Integer qSectorStart; + protected Integer qSectorEnd; + + protected int [] events; + + protected Boolean preprocessing; + + protected String function; + + public FixAccess() { + } + + public FixAccess(FLYSArtifact artifact) { + super(artifact); + } + + public Double getFrom() { + + if (from == null) { + from = getDouble("from"); + } + + if (log.isDebugEnabled()) { + log.debug("from: '" + from + "'"); + } + + return from; + } + + public Double getTo() { + + if (to == null) { + to = getDouble("to"); + } + + if (log.isDebugEnabled()) { + log.debug("to: '" + to + "'"); + } + + return to; + } + + public Double getStep() { + + if (step == null) { + step = getDouble("step"); + } + + if (log.isDebugEnabled()) { + log.debug("step: '" + step + "'"); + } + + return step; + } + + public Long getStart() { + + if (start == null) { + start = getLong("start"); + } + + if (log.isDebugEnabled()) { + log.debug("start: '" + start + "'"); + } + + return start; + } + + public Long getEnd() { + + if (end == null) { + end = getLong("end"); + } + + if (log.isDebugEnabled()) { + log.debug("end: '" + end + "'"); + } + + return end; + } + + public Integer getQSectorStart() { + + if (qSectorStart == null) { + qSectorStart = getInteger("q1"); + } + + if (log.isDebugEnabled()) { + log.debug("q1: '" + qSectorStart + "'"); + } + + return qSectorStart; + } + + public Integer getQSectorEnd() { + + if (qSectorEnd == null) { + qSectorEnd = getInteger("q2"); + } + + if (log.isDebugEnabled()) { + log.debug("q2: '" + qSectorEnd + "'"); + } + + return qSectorEnd; + } + + public int [] getEvents() { + if (events == null) { + events = getIntArray("events"); + } + if (log.isDebugEnabled() && events != null) { + log.debug("events: " + Arrays.toString(events)); + } + return events; + } + + public Boolean getPreprocessing() { + if (preprocessing == null) { + preprocessing = getBoolean("preprocessing"); + } + if (log.isDebugEnabled()) { + log.debug("preprocessing: " + preprocessing); + } + return preprocessing; + } + + public String getFunction() { + if (function == null) { + function = getString("function"); + } + if (log.isDebugEnabled()) { + log.debug("function: " + function); + } + return function; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,105 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.DateRange; + +import java.util.Arrays; +import java.util.Date; + +import org.apache.log4j.Logger; + +public class FixAnalysisAccess +extends FixAccess +{ + private static Logger log = Logger.getLogger(FixAnalysisAccess.class); + + protected DateRange referencePeriod; + protected DateRange [] analysisPeriods; + + protected double [] qs; + + public FixAnalysisAccess() { + } + + public FixAnalysisAccess(FLYSArtifact artifact) { + super(artifact); + } + + public DateRange getReferencePeriod() { + if (referencePeriod == null) { + StateData refStart = artifact.getData("ref_start"); + StateData refEnd = artifact.getData("ref_end"); + + if (refStart == null || refEnd == null) { + log.warn("missing 'ref_start' or 'ref_start' value"); + return null; + } + + try { + long rs = Long.parseLong((String)refStart.getValue()); + long re = Long.parseLong((String)refEnd .getValue()); + + if (rs > re) { long t = rs; rs = re; re = t; } + + Date from = new Date(rs); + Date to = new Date(re); + referencePeriod = new DateRange(from, to); + } + catch (NumberFormatException nfe) { + log.warn("ref_start or ref_end is not an integer."); + } + } + + return referencePeriod; + } + + public DateRange [] getAnalysisPeriods() { + if (analysisPeriods == null) { + analysisPeriods = getDateRange("ana_data"); + } + + return analysisPeriods; + } + + /** + * @return DateRange object ranging from eldest to youngest date + * of analysis and reference periods. + */ + public DateRange getDateRange() { + DateRange refP = getReferencePeriod(); + + if (refP == null) { + return null; + } + + Date from = refP.getFrom(); + Date to = refP.getTo(); + + DateRange[] rs = getAnalysisPeriods(); + for (DateRange r: rs) { + if (r.getFrom().before(from)) { + from = r.getFrom(); + } + if (r.getTo().after(to)) { + to = r.getTo(); + } + } + + return new DateRange(from, to); + } + + public double [] getQs() { + if (qs == null) { + qs = getDoubleArray("qs"); + } + + if (log.isDebugEnabled() && qs != null) { + log.debug("qs: " + Arrays.toString(qs)); + } + return qs; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,53 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.Segment; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class FixRealizingAccess +extends FixAccess +{ + private static Logger log = Logger.getLogger(FixRealizingAccess.class); + + protected Boolean isQ; + + protected List<Segment> segments; + + public FixRealizingAccess() { + } + + public FixRealizingAccess(FLYSArtifact artifact) { + super(artifact); + } + + public Boolean isQ() { + if (isQ == null) { + isQ = getBoolean("wq_isq"); + } + + if (log.isDebugEnabled()) { + log.debug("isQ: " + isQ); + } + + return isQ; + } + + public List<Segment> getSegments() { + if (segments == null) { + String segmentsS = getString("wq_values"); + if (segmentsS != null) { + segments = Segment.parseSegments(segmentsS); + } + } + if (log.isDebugEnabled()) { + log.debug("segments: " + segments); + } + + return segments; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,55 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +public class FlowVelocityAccess extends RiverAccess { + + private int[] mainChannels; + private int[] totalChannels; + + private Double lowerKM; + private Double upperKM; + + + public FlowVelocityAccess(FLYSArtifact artifact) { + super(artifact); + } + + + public int[] getMainChannels() { + if (mainChannels == null) { + mainChannels = getIntArray("main_channel"); + } + + return mainChannels; + } + + + public int[] getTotalChannels() { + if (totalChannels == null) { + totalChannels = getIntArray("total_channel"); + } + + return totalChannels; + } + + + public Double getLowerKM() { + if (lowerKM == null) { + lowerKM = getDouble("ld_from"); + } + + return lowerKM; + } + + + public Double getUpperKM() { + if (upperKM == null) { + upperKM = getDouble("ld_to"); + } + + return upperKM; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/RiverAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,31 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import org.apache.log4j.Logger; + +public class RiverAccess +extends Access +{ + private static Logger log = Logger.getLogger(RiverAccess.class); + + protected String river; + + public RiverAccess() { + } + + public RiverAccess(FLYSArtifact artifact) { + super(artifact); + } + + public String getRiver() { + if (river == null) { + river = getString("river"); + } + if (log.isDebugEnabled()) { + log.debug("river: '" + river + "'"); + } + return river; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.access; + +import java.util.Date; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.DateRange; + +public class SQRelationAccess +extends RiverAccess +{ + private static Logger log = Logger.getLogger(SQRelationAccess.class); + + protected Double location; + + protected DateRange period; + + protected Double outliers; + + public SQRelationAccess() { + } + + public SQRelationAccess(FLYSArtifact artifact) { + super(artifact); + } + + public Double getLocation() { + if (location == null) { + // XXX: The parameter name suggests plural!? + location = getDouble("ld_locations"); + } + + if (log.isDebugEnabled()) { + log.debug("location: " + location); + } + + return location; + } + + public DateRange getPeriod() { + if (period == null) { + Long start = getLong("start"); + Long end = getLong("end"); + + if (start != null && end != null) { + period = new DateRange(new Date(start), new Date(end)); + } + } + + return period; + } + + public Double getOutliers() { + if (outliers == null) { + outliers = getDouble("outliers"); + } + if (log.isDebugEnabled()) { + log.debug("outliers: " + outliers); + } + return outliers; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/cache/CacheFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,79 @@ +package de.intevation.flys.artifacts.cache; + +import de.intevation.artifacts.common.utils.Config; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheException; +import net.sf.ehcache.CacheManager; + +import org.apache.log4j.Logger; + +public final class CacheFactory +{ + private static Logger log = Logger.getLogger(CacheFactory.class); + + public static final String CACHE_CONFIG_FILE_PROPERTY = + "flys.artifacts.cache.config.file"; + + public static final String XPATH_CACHE_CONFIG_FILE = + "/artifact-database/cache/config-file/text()"; + + private CacheFactory() { + } + + private static boolean initialized; + + private static CacheManager cacheManager; + + public static final Cache getCache() { + return getCache(Cache.DEFAULT_CACHE_NAME); + } + + public static final String getConfigFile() { + String configFile = System.getProperty(CACHE_CONFIG_FILE_PROPERTY); + + if (configFile != null) { + return configFile; + } + + configFile = Config.getStringXPath(XPATH_CACHE_CONFIG_FILE); + + if (configFile != null) { + configFile = Config.replaceConfigDir(configFile); + } + + return configFile; + } + + public static final synchronized Cache getCache(String cacheName) { + if (!initialized) { + initialized = true; // try only once + String configFile = getConfigFile(); + if (configFile != null) { + try { + cacheManager = CacheManager.create(configFile); + //System.setProperty( + // "net.sf.ehcache.enableShutdownHook", "true"); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + log.info("shutting down caches"); + for (String name: cacheManager.getCacheNames()) { + log.info("\tflushing '" + name + "'"); + cacheManager.getCache(name).flush(); + } + cacheManager.shutdown(); + } + }); + } + catch (CacheException ce) { + log.error("cannot configure cache", ce); + } + } + } + + return cacheManager != null + ? cacheManager.getCache(cacheName) + : null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,701 @@ +package de.intevation.flys.artifacts.charts; + +import de.intevation.flys.backend.SessionFactoryProvider; + +import de.intevation.flys.artifacts.geom.Lines; + +import de.intevation.flys.model.CrossSection; +import de.intevation.flys.model.CrossSectionLine; +import de.intevation.flys.model.CrossSectionPoint; + +import de.intevation.flys.utils.Pair; + +import de.intevation.flys.jfree.StableXYDifferenceRenderer; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import java.math.BigDecimal; +import java.math.MathContext; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import java.awt.Color; +import java.awt.Paint; +import java.awt.TexturePaint; + +import java.awt.image.BufferedImage; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; + +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import javax.swing.table.AbstractTableModel; + +import org.hibernate.Query; +import org.hibernate.Session; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.ChartUtilities; +import org.jfree.chart.JFreeChart; + +import org.jfree.chart.axis.NumberAxis; + +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.data.xy.DefaultXYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.chart.renderer.xy.XYItemRenderer; + +import org.jfree.ui.ApplicationFrame; +import org.jfree.ui.RefineryUtilities; + +/** + * Standalone tech-demo. + */ +public class CrossSectionApp +extends ApplicationFrame +{ + public static final String RIVER = System.getProperty("river", "Saar"); + + public static final String WATER_LEVEL = System.getProperty("waterlevel"); + + public static final String KM = System.getProperty("km"); + + public static final double EPSILON = 1e-4; + + protected Session session; + + protected JComboBox crossSectionLinesCB; + protected JTextField waterlevelTF; + + protected ChartPanel chartPanel; + + protected Double lastWaterLevel; + + protected List<CrossSection> crossSections; + protected boolean [] drawCrossSection; + protected boolean [] drawWaterLevel; + protected boolean [] drawGround; + protected boolean [] drawFill; + + protected Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines; + + protected static final Paint TRANSPARENT = createTransparentPaint(); + + public class CrossSectionTableModel extends AbstractTableModel { + + @Override + public String getColumnName(int col) { + switch (col) { + case 0: return "Peilungsname"; + case 1: return "Peilung"; + case 2: return "Wasserstand"; + case 3: return "Boden"; + case 4: return "Wasser"; + } + return ""; + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public int getRowCount() { + return crossSections != null ? crossSections.size() : 0; + } + + @Override + public Object getValueAt(int row, int col) { + if (crossSections == null) return null; + switch (col) { + case 0: return crossSections.get(row).getDescription(); + case 1: return drawCrossSection[row]; + case 2: return drawWaterLevel[row]; + case 3: return drawGround[row]; + case 4: return drawFill[row]; + } + return null; + } + + @Override + public void setValueAt(Object value, int row, int col) { + switch (col) { + case 1: + if (change(drawCrossSection, row, (Boolean)value)) { + fireTableCellUpdated(row, col); + } + break; + case 2: + if (change(drawWaterLevel, row, (Boolean)value)) { + fireTableCellUpdated(row, col); + } + break; + case 3: + if (change(drawGround, row, (Boolean)value)) { + fireTableCellUpdated(row, col); + } + break; + case 4: + if (change(drawFill, row, (Boolean)value)) { + fireTableCellUpdated(row, col); + } + break; + } + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: return String.class; + case 1: + case 2: + case 3: + case 4: return Boolean.class; + } + return null; + } + + @Override + public boolean isCellEditable( + int rowIndex, + int columnIndex + ) { + return columnIndex >= 1 && columnIndex <= 4; + } + } // class CrossSectionTableModel + + private static boolean change( + boolean [] values, + int index, + boolean value + ) { + if (values[index] != value) { + values[index] = value; + return true; + } + return false; + } + + public static class CrossSectionLineItem { + + Double km; + List<Pair<CrossSection, CrossSectionLine>> lines; + + public CrossSectionLineItem( + Double km, + List<Pair<CrossSection, CrossSectionLine>> lines + ) { + this.km = km; + this.lines = lines; + } + + public String toString() { + return String.valueOf(km); + } + } // CrossSectionLineItem + + public CrossSectionApp(String title) { + super(title); + + session = SessionFactoryProvider + .createSessionFactory() + .openSession(); + + JPanel content = createContent(); + content.setPreferredSize(new Dimension(800, 480)); + setContentPane(content); + + } + + public List<CrossSection> crossSections(String river) { + Query query = session.createQuery( + "from CrossSection where river.name = :river"); + query.setParameter("river", river); + return query.list(); + } + + protected Map<Double, List<Pair<CrossSection, CrossSectionLine>>> + loadAllLines(List<CrossSection> crossSections) { + Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines = + new TreeMap<Double, List<Pair<CrossSection, CrossSectionLine>>>(); + for (CrossSection cs: crossSections) { + List<CrossSectionLine> lines = cs.getLines(); + for (CrossSectionLine csl: lines) { + Double km = Math.round(csl.getKm().doubleValue() * 1000d)/1000d; + List<Pair<CrossSection, CrossSectionLine>> ls + = km2lines.get(km); + if (ls == null) { + ls = new ArrayList<Pair<CrossSection, CrossSectionLine>>(2); + km2lines.put(km, ls); + } + ls.add(new Pair<CrossSection, CrossSectionLine>(cs, csl)); + } + } + return km2lines; + } + + public JPanel createContent() { + JPanel panel = new JPanel(new BorderLayout()); + + + JPanel nav = new JPanel(new FlowLayout()); + + crossSections = crossSections(RIVER); + km2lines = loadAllLines(crossSections); + + int CS = crossSections.size(); + Arrays.fill(drawCrossSection = new boolean[CS], true); + drawWaterLevel = new boolean[CS]; + drawGround = new boolean[CS]; + drawFill = new boolean[CS]; + + Object [] clis = createCrossSectionLineItems(km2lines); + + DefaultComboBoxModel dcbm = new DefaultComboBoxModel(clis); + + crossSectionLinesCB = new JComboBox(dcbm); + + if (KM != null) { + try { + double km = Double.parseDouble(KM); + + CrossSectionLineItem found = null; + + for (Object o: clis) { + CrossSectionLineItem csli = (CrossSectionLineItem)o; + if (Math.abs(csli.km - km) < EPSILON) { + found = csli; + break; + } + } + + if (found != null) { + crossSectionLinesCB.setSelectedItem(found); + } + } + catch (NumberFormatException nfe) { + System.err.println("km is not a number: " + + nfe.getMessage()); + } + } + + nav.add(crossSectionLinesCB); + + crossSectionLinesCB.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent ie) { + if (ie.getStateChange() == ItemEvent.SELECTED) { + updateChart(); + } + } + }); + + waterlevelTF = new JTextField(5); + + if (WATER_LEVEL != null) { + try { + waterlevelTF.setText( + (lastWaterLevel = Double.valueOf(WATER_LEVEL)).toString()); + } + catch (NumberFormatException nfe) { + System.err.println("Water level not a number: " + + nfe.getMessage()); + } + } + + waterlevelTF.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + waterLevelChanged(); + } + }); + + nav.add(waterlevelTF); + + JButton dump = new JButton("dump"); + + dump.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + dumpData(); + } + }); + + nav.add(dump); + + + chartPanel = createChartPanel(); + + panel.add(chartPanel, BorderLayout.CENTER); + + + CrossSectionTableModel cstm = new CrossSectionTableModel(); + + cstm.addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + updateChart(); + } + }); + + JTable crossTable = new JTable(cstm); + + JPanel west = new JPanel(new BorderLayout()); + JScrollPane scrollPane = new JScrollPane(crossTable); + west.add(scrollPane); + + west.add(nav, BorderLayout.SOUTH); + + panel.add(west, BorderLayout.WEST); + + return panel; + } + + protected void waterLevelChanged() { + String value = waterlevelTF.getText(); + try { + lastWaterLevel = Double.valueOf(value); + } + catch (NumberFormatException nfe) { + waterlevelTF.setText( + lastWaterLevel != null ? lastWaterLevel.toString() : ""); + return; + } + updateChart(); + } + + protected void updateChart() { + + CrossSectionLineItem csli = + (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); + + JFreeChart chart = createChart(); + + chartPanel.setChart(chart); + } + + protected ChartPanel createChartPanel() { + CrossSectionLineItem csli = + (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); + + JFreeChart chart = createChart(); + + return new ChartPanel(chart); + } + + protected void dumpData() { + + CrossSectionLineItem csli = + (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); + + if (csli == null) { + return; + } + + + double km = Math.round(csli.km.doubleValue() * 1000d)/1000d; + + String kmS = String.valueOf(km).replace(".", "-"); + + int i = 1; + File file = new File("cross-section-" + kmS + ".txt"); + while (file.exists()) { + file = new File("cross-section-" + kmS + "[" + (i++) + "].txt"); + } + + System.err.println("dump points to file '" + file + "'"); + + PrintWriter out = null; + + MathContext mc = new MathContext(3); + + try { + out = + new PrintWriter( + new FileWriter(file)); + + for (Pair<CrossSection, CrossSectionLine> pair: csli.lines) { + out.println("# " + pair.getA().getDescription()); + for (CrossSectionPoint point: pair.getB().getPoints()) { + out.println( + new BigDecimal(point.getX()).round(mc) + " " + + new BigDecimal(point.getY()).round(mc)); + } + } + + out.flush(); + } + catch (IOException ioe) { + ioe.printStackTrace(); + } + finally { + if (out != null) { + out.close(); + } + } + } + + public void generateWaterLevels( + List<Point2D> points, + List<Pair<XYDataset, XYItemRenderer>> datasets + ) { + if (points == null || points.isEmpty() || lastWaterLevel == null) { + return; + } + + double [][] data = Lines.createWaterLines(points, lastWaterLevel).points; + XYSeries series = + new XYSeries(String.valueOf(lastWaterLevel), false); + + double [] x = data[0]; + double [] y = data[1]; + for (int i = 0; i < x.length; ++i) { + series.add(x[i], y[i], false); + } + + datasets.add(new Pair<XYDataset, XYItemRenderer>( + new XYSeriesCollection(series), null)); + } + + public void generateFill( + List<Point2D> points, + String legend, + List<Pair<XYDataset, XYItemRenderer>> datasets + ) { + if (points == null || points.isEmpty() || lastWaterLevel == null) { + return; + } + + double [][] data = Lines.createWaterLines(points, lastWaterLevel).points; + double [][] values = CrossSectionLine.fetchCrossSectionProfile(points); + + DefaultXYDataset dataset = new DefaultXYDataset(); + + dataset.addSeries(legend + "-Linie", values); + dataset.addSeries(legend + "-Fl\u00e4che", data); + + datasets.add(new Pair<XYDataset, XYItemRenderer>( + dataset, + new StableXYDifferenceRenderer( + TRANSPARENT, Color.blue, false))); + } + + public void generateProfile( + List<Point2D> points, + String legend, + List<Pair<XYDataset, XYItemRenderer>> datasets + ) { + if (points == null || points.isEmpty()) { + return; + } + + double [][] values = CrossSectionLine.fetchCrossSectionProfile(points); + + XYSeries series = new XYSeries(legend, false); + + double [] x = values[0]; + double [] y = values[1]; + for (int i = 0; i < x.length; ++i) { + series.add(x[i], y[i], false); + } + + datasets.add(new Pair<XYDataset, XYItemRenderer>( + new XYSeriesCollection(series), null));; + } + + + /** + * @param legend the legend entry. + */ + public void generateGround( + List<Point2D> points, + String legend, + List<Pair<XYDataset, XYItemRenderer>> datasets + ) { + if (points == null || points.isEmpty()) { + return; + } + + double [][] values = CrossSectionLine.fetchCrossSectionProfile(points); + + DefaultXYDataset dataset = new DefaultXYDataset(); + + XYSeries series = new XYSeries(legend, false); + + dataset.addSeries(legend, values); + + StableXYDifferenceRenderer renderer = + new StableXYDifferenceRenderer(); + + datasets.add(new Pair<XYDataset, XYItemRenderer>( + dataset, renderer)); + } + + public List<Pair<XYDataset, XYItemRenderer>> generateDatasets() { + + List<Pair<XYDataset, XYItemRenderer>> datasets = + new ArrayList<Pair<XYDataset, XYItemRenderer>>(); + + CrossSectionLineItem csli = + (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); + + for (int i = 0; i < drawCrossSection.length; ++i) { + List<Point2D> points = null; + CrossSection cs = crossSections.get(i); + + if (drawGround[i]) { + for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { + if (csl.getA() == cs) { + if (points == null) { + points = csl.getB().fetchCrossSectionLinesPoints(); + } + generateGround( + points, + cs.getDescription() + "/Boden", + datasets); + break; + } + } + } + + if (drawFill[i]) { + for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { + if (csl.getA() == cs) { + if (points == null) { + points = csl.getB().fetchCrossSectionLinesPoints(); + } + + generateFill( + points, cs.getDescription(), datasets); + break; + } + } + } + + if (drawCrossSection[i]) { + for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { + if (csl.getA() == cs) { + if (points == null) { + points = csl.getB().fetchCrossSectionLinesPoints(); + } + + generateProfile( + points, cs.getDescription(), datasets); + break; + } + } + } + + if (drawWaterLevel[i]) { + for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { + if (csl.getA() == cs) { + if (points == null) { + points = csl.getB().fetchCrossSectionLinesPoints(); + } + generateWaterLevels(points, datasets); + break; + } + } + } + + } + + return datasets; + } + + protected Object [] createCrossSectionLineItems( + Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines + ) { + Object [] result = new Object[km2lines.size()]; + int i = 0; + for (Map.Entry<Double, List<Pair<CrossSection, CrossSectionLine>>> entry: + km2lines.entrySet()) { + result[i++] = new CrossSectionLineItem( + entry.getKey(), + entry.getValue()); + } + return result; + } + + + public JFreeChart createChart() { + JFreeChart chart = ChartFactory.createXYLineChart( + null, + "Abstand [m]", + "H\u00f6he [m]", + null, + PlotOrientation.VERTICAL, + true, + true, + false); + + List<Pair<XYDataset, XYItemRenderer>> datasets = + generateDatasets(); + + XYPlot plot = chart.getXYPlot(); + + for (int i = 0, N = datasets.size(); i < N; ++i) { + Pair<XYDataset, XYItemRenderer> p = datasets.get(i); + plot.setDataset(i, p.getA()); + plot.mapDatasetToRangeAxis(i, 0); + XYItemRenderer renderer = p.getB(); + if (renderer != null) { + plot.setRenderer(i, renderer); + } + } + + NumberAxis yAxis = (NumberAxis)plot.getRangeAxis(); + yAxis.setAutoRangeIncludesZero(false); + + ChartUtilities.applyCurrentTheme(chart); + return chart; + } + + protected static Paint createTransparentPaint() { + BufferedImage texture = new BufferedImage( + 1, 1, BufferedImage.TYPE_4BYTE_ABGR); + + return new TexturePaint( + texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); + } + + public static void main(String [] args) { + CrossSectionApp csa = new CrossSectionApp("Querprofile"); + csa.pack(); + RefineryUtilities.centerFrameOnScreen(csa); + csa.setVisible(true); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/TimeseriesStepChart.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,218 @@ +package de.intevation.flys.artifacts.charts; + +import java.awt.Dimension; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.ui.ApplicationFrame; + +import org.jfree.data.time.SimpleTimePeriod; +import org.jfree.data.time.Second; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.time.TimePeriodValues; +import org.jfree.data.time.TimePeriodValuesCollection; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; + + +public class TimeseriesStepChart extends ApplicationFrame { + + private static final Logger logger = + Logger.getLogger(TimeseriesStepChart.class); + + + public static final String LOG4J_PROPERTIES = "FLYS_CLIENT_LOG4J_PROPERIES"; + + public static final int USER_CHART_TYPE = + Integer.getInteger("chart.type", -1); + + public static final int CHART_TYPE_TIMEPERIOD = 1; + public static final int CHART_TYPE_TIMESERIES = 2; + + + public static void main(String[] args) { + configureLogging(); + + logger.info("Start TimeseriesStepChart demo."); + + if (USER_CHART_TYPE <= 0) { + logger.error("Unknown chart type: " + USER_CHART_TYPE); + } + + logger.debug("Create Chart from type: " + USER_CHART_TYPE); + + TimeseriesStepChart tsc = new TimeseriesStepChart(); + tsc.build(USER_CHART_TYPE); + + logger.info("End of TimeseriesStepChart demo."); + } + + + public static void configureLogging() { + String log4jProperties = System.getenv(LOG4J_PROPERTIES); + + if (log4jProperties != null && log4jProperties.length() > 0) { + PropertyConfigurator.configure(log4jProperties); + logger.info("Log4J logging initialized."); + } + else { + System.out.println("Error while setting up Log4J configuration."); + } + + System.out.println("LoggingConfigurator.init finished"); + } + + + public TimeseriesStepChart() { + super("TimeseriesStepChart"); + } + + + public void build(int type) { + ChartPanel chartPanel = createChartPanel(type); + chartPanel.setPreferredSize(new Dimension(500, 300)); + + setContentPane(chartPanel); + + pack(); + setVisible(true); + } + + + protected ChartPanel createChartPanel(int type) { + JFreeChart chart = createJFreeChart(type); + ChartPanel panel = new ChartPanel(chart); + return panel; + } + + + protected JFreeChart createJFreeChart(int type) { + if (type == CHART_TYPE_TIMEPERIOD) { + return createTimePeriodValuesChart(); + } + else if (type == CHART_TYPE_TIMESERIES) { + return createTimeSeriesChart(); + } + + logger.error("Unknown chart type: " + type); + + return null; + } + + + public static Date createDate(int year, int month, int day) { + GregorianCalendar cal = new GregorianCalendar(year, month, day); + return cal.getTime(); + } + + + + // + // XXX FOLLOWING METHODS ARE USED FOR "TimePeriodValues" CHART TYPE + // + protected JFreeChart createTimePeriodValuesChart() { + return ChartFactory.createTimeSeriesChart( + "TimePeriodValues Chart", + "Time Axis", + "Y Axis", + createTimePeriodValuesDataset(), + true, + false, + false); + } + + + protected TimePeriodValuesCollection createTimePeriodValuesDataset() { + TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); + TimePeriodValues series = createTimePeriodValues(); + + dataset.addSeries(series); + + return dataset; + } + + + protected TimePeriodValues createTimePeriodValues() { + TimePeriodValues series1 = new TimePeriodValues("Series 1"); + + Date start1 = createDate(2000, 0, 1); + Date end1 = createDate(2000, 11, 31); + + logger.debug("START DATE 1 = " + start1); + logger.debug("END DATE 1 = " + end1); + + SimpleTimePeriod period1 = new SimpleTimePeriod(start1, end1); + + Date start2 = createDate(2001, 0, 1); + Date end2 = createDate(2001, 11, 31); + SimpleTimePeriod period2 = new SimpleTimePeriod(start2, end2); + + Date start3 = createDate(2002, 0, 1); + Date end3 = createDate(2002, 11, 31); + SimpleTimePeriod period3 = new SimpleTimePeriod(start3, end3); + + series1.add(period1, 100); + series1.add(period2, 200); + series1.add(period3, 150); + + return series1; + } + + + // + // XXX FOLLOWING METHODS ARE USED FOR "TimePeriodValues" CHART TYPE + // + protected JFreeChart createTimeSeriesChart() { + return ChartFactory.createTimeSeriesChart( + "TimeSeriesCollection Chart", + "Time Axis", + "Y Axis", + createTimeSeriesCollectionDataset(), + true, + false, + false); + } + + + protected TimeSeriesCollection createTimeSeriesCollectionDataset() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + TimeSeries[] series = createTimeSeries(); + + for (TimeSeries tmp: series) { + dataset.addSeries(tmp); + } + + return dataset; + } + + + protected TimeSeries[] createTimeSeries() { + TimeSeries series1 = new TimeSeries("Series 1"); + series1.add(new Second(0, 0, 0, 1, 1, 2000), 100); + series1.add(new Second(59, 59, 23, 31, 12, 2000), 100); + + series1.add(new Second(0, 0, 0, 1, 1, 2001), 200); + series1.add(new Second(59, 59, 23, 31, 12, 2001), 200); + + series1.add(new Second(0, 0, 0, 1, 1, 2002), 150); + series1.add(new Second(59, 59, 23, 31, 12, 2002), 150); + + TimeSeries series2 = new TimeSeries("Series 2"); + series2.add(new Second(0, 0, 0, 1, 1, 2000), 10); + series2.add(new Second(59, 59, 23, 31, 12, 2000), 10); + + series2.add(new Second(0, 0, 0, 1, 1, 2001), 20); + series2.add(new Second(59, 59, 23, 31, 12, 2001), 20); + + series2.add(new Second(0, 0, 0, 1, 1, 2002), 15); + series2.add(new Second(59, 59, 23, 31, 12, 2002), 15); + + return new TimeSeries[] { series1, series2 }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,116 @@ +package de.intevation.flys.artifacts.context; + +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.DefaultArtifactContext; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.exports.OutGenerator; + + +/** + * This class is used to store application wide information in a global context. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FLYSContext extends DefaultArtifactContext { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(FLYSContext.class); + + /** The key that is used to store the StateEngine in the context. */ + public static final String ARTIFACT_KEY = + "artifact"; + + /** The key that is used to store the TransitionEngine in the context. */ + public static final String TRANSITION_ENGINE_KEY = + "artifact.transition.engine"; + + /** The key that is used to store the StateEngine in the context. */ + public static final String STATE_ENGINE_KEY = + "artifact.state.engine"; + + /** The key that is used to store the Map of OutGenerator classes in the + * context. */ + public static final String OUTGENERATORS_KEY = + "flys.export.outgenerators"; + + /** The key that is used to store the map of themes in the context. */ + public static final String THEMES = + "flys.themes.map"; + + /** The key that is used to store a map of theme mappings in the context. */ + public static final String THEME_MAPPING = + "flys.themes.mapping.map"; + + /** The key that is used to store a map of WMS urls for each river. */ + public static final String RIVER_WMS = + "flys.floodmap.river.wms"; + + /** The key that is used to store an instance of Scheduler in the context.*/ + public static final String SCHEDULER = + "flys.wsplgen.scheduler"; + + /** Key to store the configured modules in the context. */ + public static final String MODULES = "flys.modules"; + + + /** + * The default constructor. + */ + public FLYSContext() { + super(); + } + + + /** + * A constructor with a config document. + */ + public FLYSContext(Document config) { + super(config); + } + + /** + * Returns the OutGenerator for a specified <i>type</i>. + * + * @param name The name of the output type. + * @param type Defines the type of the desired OutGenerator. + * + * @return Instance of an OutGenerator for specified <i>type</i>. + */ + public static OutGenerator getOutGenerator( + CallContext context, + String name, + String type) + { + + FLYSContext flysContext = context instanceof FLYSContext + ? (FLYSContext) context + : (FLYSContext) context.globalContext(); + + Map<String, Class> generators = (Map<String, Class>) + flysContext.get(FLYSContext.OUTGENERATORS_KEY); + + if (generators == null) { + return null; + } + + Class clazz = generators.get(name); + + try { + return clazz != null ? (OutGenerator) clazz.newInstance() : null; + } + catch (InstantiationException ie) { + logger.error(ie, ie); + } + catch (IllegalAccessException iae) { + logger.error(iae, iae); + } + + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,457 @@ +package de.intevation.flys.artifacts.context; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifacts.ArtifactContextFactory; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifactdatabase.transition.Transition; +import de.intevation.artifactdatabase.transition.TransitionEngine; + +import de.intevation.flys.artifacts.model.Module; +import de.intevation.flys.artifacts.states.StateFactory; +import de.intevation.flys.artifacts.transitions.TransitionFactory; +import de.intevation.flys.themes.Theme; +import de.intevation.flys.themes.ThemeGroup; +import de.intevation.flys.themes.ThemeFactory; +import de.intevation.flys.themes.ThemeMapping; + + +/** + * The ArtifactContextFactory is used to initialize basic components and put + * them into the global context of the application. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FLYSContextFactory implements ArtifactContextFactory { + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(FLYSContextFactory.class); + + /** The XPath to the artifacts configured in the configuration. */ + public static final String XPATH_ARTIFACTS = + "/artifact-database/artifacts/artifact"; + + /** The XPath to the name of the artifact. */ + public static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; + + /** The XPath to the xlink ref in an artifact configuration. */ + public static final String XPATH_XLINK = "xlink:href"; + + /** The XPath to the transitions configured in the artifact config. */ + public static final String XPATH_TRANSITIONS = + "/artifact/states/transition"; + + /** The XPath to the states configured in the artifact config. */ + public static final String XPATH_STATES = + "/artifact/states/state"; + + public static final String XPATH_OUTPUT_GENERATORS = + "/artifact-database/output-generators/output-generator"; + + public static final String XPATH_THEME_CONFIG = + "/artifact-database/flys/themes/configuration/text()"; + + public static final String XPATH_THEMES = + "theme"; + + public static final String XPATH_THEME_GROUPS = + "/themes/themegroup"; + + public static final String XPATH_THEME_MAPPINGS = + "/themes/mappings/mapping"; + + public static final String XPATH_RIVER_WMS = + "/artifact-database/floodmap/river"; + + public static final String XPATH_MODULES = "/artifact-database/modules/module"; + + /** + * Creates a new FLYSArtifactContext object and initialize all + * components required by the application. + * + * @param config The artifact server configuration. + * @return a FLYSArtifactContext. + */ + public GlobalContext createArtifactContext(Document config) { + FLYSContext context = new FLYSContext(config); + + configureTransitions(config, context); + configureStates(config, context); + configureOutGenerators(config, context); + configureThemes(config, context); + configureThemesMappings(config, context); + configureRiverWMS(config, context); + configureModules(config, context); + + return context; + } + + + /** + * This method initializes the transition configuration. + * + * @param config the config document. + * @param context the FLYSContext. + */ + protected void configureTransitions(Document config, FLYSContext context) { + TransitionEngine engine = new TransitionEngine(); + + Document[] artifacts = getArtifactConfigurations(config); + logger.info("Found " + artifacts.length + " artifacts in the config."); + + for (Document doc: artifacts) { + List<Transition> transitions = new ArrayList<Transition>(); + + String artName = (String) XMLUtils.xpath( + doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + + NodeList list = (NodeList) XMLUtils.xpath( + doc, XPATH_TRANSITIONS, XPathConstants.NODESET); + + if (list == null) { + logger.warn("The artifact " + artName + + " has no transitions configured."); + continue; + } + + int trans = list.getLength(); + + logger.info( + "Artifact '" + artName + "' has " + trans + " transitions."); + + for (int i = 0; i < trans; i++) { + Transition t = TransitionFactory.createTransition(list.item(i)); + String s = t.getFrom(); + engine.addTransition(s, t); + } + } + + context.put(FLYSContext.TRANSITION_ENGINE_KEY, engine); + } + + + /** + * This method returns all artifact documents defined in + * <code>config</code>. <br>NOTE: The artifact configurations need to be + * stored in own files referenced by an xlink. + * + * @param config The global configuration. + * + * @return an array of Artifact configurations. + */ + protected Document[] getArtifactConfigurations(Document config) { + NodeList artifacts = (NodeList) XMLUtils.xpath( + config, XPATH_ARTIFACTS, XPathConstants.NODESET); + + int count = artifacts.getLength(); + + Document[] artifactDocs = new Document[count]; + + for (int i = 0; i < count; i++) { + Element tmp = (Element) artifacts.item(i); + + String xlink = tmp.getAttribute(XPATH_XLINK); + xlink = Config.replaceConfigDir(xlink); + + File artifactFile = new File(xlink); + artifactDocs[i] = XMLUtils.parseDocument(artifactFile); + } + + return artifactDocs; + } + + + /** + * This method initializes the transition configuration. + * + * @param config the config document. + * @param context the FLYSContext. + */ + protected void configureStates(Document config, FLYSContext context) { + StateEngine engine = new StateEngine(); + + Document[] artifacts = getArtifactConfigurations(config); + logger.info("Found " + artifacts.length + " artifacts in the config."); + + for (Document doc: artifacts) { + List<State> states = new ArrayList<State>(); + + String artName = (String) XMLUtils.xpath( + doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + + NodeList stateList = (NodeList) XMLUtils.xpath( + doc, XPATH_STATES, XPathConstants.NODESET); + + if (stateList == null) { + logger.warn("The artifact " + artName + + " has no states configured."); + continue; + } + + int count = stateList.getLength(); + + logger.info( + "Artifact '" + artName + "' has " + count + " states."); + + for (int i = 0; i < count; i++) { + states.add(StateFactory.createState( + stateList.item(i))); + } + + engine.addStates(artName, states); + } + + context.put(FLYSContext.STATE_ENGINE_KEY, engine); + } + + + /** + * This method intializes the provided output generators. + * + * @param config the config document. + * @param context the FLYSContext. + */ + protected void configureOutGenerators(Document config, FLYSContext context){ + Map<String, Class> generators = new HashMap<String, Class>(); + + NodeList outGenerators = (NodeList) XMLUtils.xpath( + config, + XPATH_OUTPUT_GENERATORS, + XPathConstants.NODESET); + + int num = outGenerators == null ? 0 : outGenerators.getLength(); + + if (num == 0) { + logger.warn("No output generators configured in this application."); + return; + } + + logger.info("Found " + num + " configured output generators."); + + int idx = 0; + + for (int i = 0; i < num; i++) { + Node item = outGenerators.item(i); + + String name = (String) XMLUtils.xpath( + item, "@name", XPathConstants.STRING); + + String clazz = (String) XMLUtils.xpath( + item, "text()", XPathConstants.STRING); + + if (name == null || clazz == null) { + continue; + } + + try { + generators.put(name, Class.forName(clazz)); + + idx++; + } + catch (ClassNotFoundException cnfe) { + logger.warn(cnfe, cnfe); + } + } + + logger.info("Successfully loaded " + idx + " output generators."); + context.put(FLYSContext.OUTGENERATORS_KEY, generators); + } + + + /** + * This methods reads the configured themes and puts them into the + * FLYSContext. + * + * @param config The global configuration. + * @param context The FLYSContext. + */ + protected void configureThemes(Document config, FLYSContext context) { + logger.debug("FLYSContextFactory.configureThemes"); + + Document cfg = getThemeConfig(config); + + NodeList themeGroups = (NodeList) XMLUtils.xpath( + cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); + + int groupNum = themeGroups != null ? themeGroups.getLength() : 0; + + if (groupNum == 0) { + logger.warn("There are no theme groups configured!"); + } + + logger.info("Found " + groupNum + " theme groups in configuration"); + + List<ThemeGroup> groups = new ArrayList<ThemeGroup>(); + + for (int g = 0; g < groupNum; g++) { + Element themeGroup = (Element) themeGroups.item(g); + NodeList themes = (NodeList) XMLUtils.xpath( + themeGroup, XPATH_THEMES, XPathConstants.NODESET); + + int num = themes != null ? themes.getLength() : 0; + + if (num == 0) { + logger.warn("There are no themes configured!"); + return; + } + + logger.info("Theme group has " + num + " themes."); + + Map<String, Theme> theThemes = new HashMap<String, Theme>(); + + for (int i = 0; i < num; i++) { + Node theme = themes.item(i); + + Theme theTheme = ThemeFactory.createTheme(cfg, theme); + + if (theme != null) { + theThemes.put(theTheme.getName(), theTheme); + } + } + String gName = themeGroup.getAttribute("name"); + groups.add(new ThemeGroup(gName, theThemes)); + + logger.info( + "Initialized " + theThemes.size() + "/" + num + " themes " + + "of theme-group '" + gName + "'"); + } + context.put(FLYSContext.THEMES, groups); + } + + /** + * This method is used to retrieve the theme configuration document. + * + * @param config The global configuration. + * + * @return the theme configuration. + */ + protected Document getThemeConfig(Document config) { + String themeConfig = (String) XMLUtils.xpath( + config, + XPATH_THEME_CONFIG, + XPathConstants.STRING); + + themeConfig = Config.replaceConfigDir(themeConfig); + + logger.debug("Parse theme cfg: " + themeConfig); + + return XMLUtils.parseDocument(new File(themeConfig)); + } + + + protected void configureThemesMappings(Document cfg, FLYSContext context) { + logger.debug("FLYSContextFactory.configureThemesMappings"); + + Document config = getThemeConfig(cfg); + + NodeList mappings = (NodeList) XMLUtils.xpath( + config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); + + int num = mappings != null ? mappings.getLength() : 0; + + if (num == 0) { + logger.warn("No theme <--> facet mappins found!"); + return; + } + + Map<String, List<ThemeMapping>> mapping = + new HashMap<String, List<ThemeMapping>>(); + + for (int i = 0; i < num; i++) { + Element node = (Element)mappings.item(i); + + String from = node.getAttribute("from"); + String to = node.getAttribute("to"); + String pattern = node.getAttribute("pattern"); + String masterAttrPattern = node.getAttribute("masterAttr"); + String outputPattern = node.getAttribute("output"); + + if (from.length() > 0 && to.length() > 0) { + List<ThemeMapping> tm = mapping.get(from); + + if (tm == null) { + tm = new ArrayList<ThemeMapping>(); + mapping.put(from, tm); + } + + tm.add(new ThemeMapping( + from, to, pattern, masterAttrPattern, outputPattern)); + } + } + + logger.debug("Found " + mapping.size() + " theme mappings."); + + context.put(FLYSContext.THEME_MAPPING, mapping); + } + + + protected void configureRiverWMS(Document cfg, FLYSContext context) { + Map<String, String> riverWMS = new HashMap<String, String>(); + + NodeList rivers = (NodeList) XMLUtils.xpath( + cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); + + int num = rivers != null ? rivers.getLength() : 0; + + for (int i = 0; i < num; i++) { + Element e = (Element) rivers.item(i); + + String river = e.getAttribute("name"); + String url = XMLUtils.xpathString(e, "river-wms/@url", null); + + if (river != null && url != null) { + riverWMS.put(river, url); + } + } + + logger.debug("Found " + riverWMS.size() + " river WMS."); + + context.put(FLYSContext.RIVER_WMS, riverWMS); + } + + + /** + * This method initializes the modules configuration. + * + * @param config the config document. + * @param context the FLYSContext. + */ + protected void configureModules(Document cfg, FLYSContext context) { + NodeList modulenodes = (NodeList) XMLUtils.xpath( + cfg, XPATH_MODULES, XPathConstants.NODESET); + + int num = modulenodes != null ? modulenodes.getLength() : 0; + ArrayList<Module> modules = new ArrayList<Module>(num); + + for (int i = 0; i < num; i++) { + Element e = (Element) modulenodes.item(i); + String modulename = e.getAttribute("name"); + String attrselected = e.getAttribute("selected"); + boolean selected = attrselected == null ? false : + attrselected.equalsIgnoreCase("true"); + logger.debug("Loaded module " + modulename); + modules.add(new Module(modulename, selected)); + } + context.put(FLYSContext.MODULES, modules); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,68 @@ +package de.intevation.flys.artifacts.context; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import org.hibernate.Session; + +import de.intevation.flys.backend.SessionHolder; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallContext.Listener; + + +/** + * This CallContextListener is used to initialize a ThreadLocal variable in + * each CallContext (for each request) that holds Sessions. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SessionCallContextListener implements Listener { + + public static final String SESSION_KEY = "context.session"; + + /** The logger that is used in this class.*/ + private static Logger logger = + Logger.getLogger(SessionCallContextListener.class); + + + public SessionCallContextListener() { + } + + + public void setup(Document config, Node listenerConfig) { + // nothing to do here + } + + + /** + * Initializes a ThreadLocal variable that is used to hold sessions. + * + * @param context The CallContext. + */ + public void init(CallContext context) { + logger.debug("SessionCallContextListener.init"); + + Session session = SessionHolder.acquire(); + + context.putContextValue(SESSION_KEY, session); + } + + + /** + * Closes open sessions of the ThreadLocal variable opened in init(). + * + * @param context The CallContext. + */ + public void close(CallContext context) { + logger.debug("SessionCallContextListener.close"); + + Session session = (Session)context.getContextValue(SESSION_KEY); + session.close(); + + SessionHolder.release(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DBConfig.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,108 @@ +package de.intevation.flys.artifacts.datacage; + +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.artifactdatabase.db.SQL; +import de.intevation.artifactdatabase.db.DBConnection; + +import org.apache.log4j.Logger; + +public class DBConfig +{ + private static Logger logger = Logger.getLogger(DBConfig.class); + + /** + * XPath to access the database driver within the global configuration. + */ + public static final String DB_DRIVER = + "/artifact-database/datacage/driver/text()"; + /** + * XPath to access the database URL within the global configuration. + */ + public static final String DB_URL = + "/artifact-database/datacage/url/text()"; + /** + * XPath to access the database use within the global configuration. + */ + public static final String DB_USER = + "/artifact-database/datacage/user/text()"; + /** + * XPath to access the database password within the global configuration. + */ + public static final String DB_PASSWORD = + "/artifact-database/datacage/password/text()"; + + /** + * The default database driver: H2 + */ + public static final String DEFAULT_DRIVER = + "org.h2.Driver"; + + /** + * The default database user: "" + */ + public static final String DEFAULT_USER = ""; + + /** + * The default database password: "" + */ + public static final String DEFAULT_PASSWORD = ""; + + + public static final String DEFAULT_URL = + "jdbc:h2:mem:datacage;INIT=RUNSCRIPT FROM '${artifacts.config.dir}/datacage.sql'"; + + public static final String RESOURCE_PATH = "/datacage-sql"; + + private static DBConfig instance; + + protected DBConnection dbConnection; + protected SQL sql; + + public DBConfig() { + } + + public DBConfig(DBConnection dbConnection, SQL sql) { + this.dbConnection = dbConnection; + this.sql = sql; + } + + public static synchronized DBConfig getInstance() { + if (instance == null) { + instance = createInstance(); + } + return instance; + } + + protected static DBConfig createInstance() { + String driver = Config.getStringXPath( + DB_DRIVER, DEFAULT_DRIVER); + + String url = Config.getStringXPath( + DB_URL, DEFAULT_URL); + + url = Config.replaceConfigDir(url); + + String user = Config.getStringXPath( + DB_USER, DEFAULT_USER); + + String password = Config.getStringXPath( + DB_PASSWORD, DEFAULT_PASSWORD); + + DBConnection dbConnection = new DBConnection( + driver, url, user, password); + + SQL sql = new SQL(DBConfig.class, RESOURCE_PATH, driver); + + return new DBConfig(dbConnection, sql); + } + + public DBConnection getDBConnection() { + return dbConnection; + } + + public SQL getSQL() { + return sql; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1073 @@ +package de.intevation.flys.artifacts.datacage; + +import java.util.Collection; +import java.util.List; +import java.util.Date; + +import java.sql.SQLException; +import java.sql.PreparedStatement; +import java.sql.Types; +import java.sql.Timestamp; + +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.ArtifactCollection; +import de.intevation.artifacts.User; + +import de.intevation.artifactdatabase.db.SQL; +import de.intevation.artifactdatabase.db.SQLExecutor; + +import de.intevation.artifactdatabase.LifetimeListener; +import de.intevation.artifactdatabase.Backend; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.artifacts.common.utils.LRUCache; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +public class Datacage +implements LifetimeListener +{ + private static Logger log = Logger.getLogger(Datacage.class); + + public static final String DATACAGE_KEY = + "global.datacage.instance"; + + public static final String ARTEFACT_DATABASE_KEY = + "global.artifact.database"; + + private String SQL_DELETE_ALL_USERS = "delete.all.users"; + private String SQL_DELETE_ALL_ARTIFACTS = "delete.all.artifacts"; + private String SQL_USER_ID_NEXTVAL = "user.id.nextval"; + private String SQL_USER_BY_GID = "user.by.gid"; + private String SQL_INSERT_USER = "insert.user"; + private String SQL_COLLECTION_BY_GID = "collection.by.gid"; + private String SQL_COLLECTION_ID_NEXTVAL = "collection.id.nextval"; + private String SQL_INSERT_COLLECTION = "insert.collection"; + private String SQL_ARTIFACT_BY_GID = "artifact.by.gid"; + private String SQL_COLLECTION_ITEM_ID_NEXTVAL = + "collection.item.id.nextval"; + private String SQL_INSERT_COLLECTION_ITEM = "insert.collection.item"; + private String SQL_ARTIFACT_ID_NEXTVAL = "artifact.id.nextval"; + private String SQL_INSERT_ARTIFACT = "insert.artifact"; + private String SQL_ARTIFACT_DATA_ID_NEXTVAL = "artifact.data.id.nextval"; + private String SQL_INSERT_ARTIFACT_DATA = "insert.artifact.data"; + private String SQL_OUT_ID_NEXTVALUE = "out.id.nextval"; + private String SQL_INSERT_OUT = "insert.out"; + private String SQL_FACET_ID_NEXTVAL = "facet.id.nextval"; + private String SQL_INSERT_FACET = "insert.facet"; + private String SQL_UPDATE_COLLECTION_NAME = "update.collection.name"; + private String SQL_DELETE_ARTIFACT_FROM_COLLECTION = + "delete.artifact.from.collection"; + private String SQL_DELETE_COLLECTION_BY_GID = + "delete.collection.by.gid"; + private String SQL_DELETE_USER_BY_GID = "delete.user.by.gid"; + private String SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID = + "delete.artifact.data.by.artifact.id"; + private String SQL_DELETE_OUTS_BY_ARTIFACT_ID = + "delete.outs.by.artifact.id"; + private String SQL_DELETE_FACETS_BY_ARTIFACT_ID = + "delete.facets.by.artifact.id"; + private String SQL_DELETE_ARTIFACT_BY_GID = + "delete.artifact.by.gid"; + + protected SQLExecutor sqlExecutor; + + public class InitialScan + implements ArtifactDatabase.ArtifactLoadedCallback + { + protected LRUCache<String, Integer> users; + protected LRUCache<String, Integer> collections; + protected LRUCache<String, Integer> artifacts; + + protected GlobalContext context; + + public InitialScan() { + users = new LRUCache<String, Integer>(); + collections = new LRUCache<String, Integer>(); + artifacts = new LRUCache<String, Integer>(); + } + + public InitialScan(GlobalContext context) { + this(); + this.context = context; + } + + @Override + public void artifactLoaded( + String userId, + String collectionId, + String collectionName, + Date collectionCreated, + String artifactId, + Date artifactCreated, + Artifact artifact + ) { + if (!(artifact instanceof FLYSArtifact)) { + log.warn("ignoring none FLYS artifacts"); + return; + } + + FLYSArtifact flysArtifact = (FLYSArtifact)artifact; + + Integer uId = getUserId(userId); + Integer cId = getCollectionId( + collectionId, uId, collectionName, collectionCreated); + + storeArtifact(artifactId, cId, flysArtifact, artifactCreated); + } + + protected Integer getId( + LRUCache<String, Integer> cache, + final String idString, + final String selectById + ) { + Integer id = cache.get(idString); + if (id != null) { + return id; + } + + final Integer [] res = new Integer[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(selectById); + stmnt.setString(1, idString); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + res[0] = result.getInt(1); + return true; + } + }; + + if (exec.runRead()) { + cache.put(idString, res[0]); + return res[0]; + } + + return null; + } + + protected void storeArtifact( + final String artifactId, + Integer collectionId, + final FLYSArtifact artifact, + final Date artifactCreated + ) { + Integer aId = getId(artifacts, artifactId, SQL_ARTIFACT_BY_GID); + + if (aId != null) { + // We've already stored it. Just create the collection item. + storeCollectionItem(collectionId, aId); + return; + } + // We need to write it to database + + final Integer [] res = new Integer[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_ARTIFACT_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + res[0] = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_ARTIFACT); + stmnt.setInt (1, res[0]); + stmnt.setString(2, artifactId); + stmnt.setString(3, artifact.getCurrentStateId()); + Timestamp timestamp = new Timestamp(artifactCreated != null + ? artifactCreated.getTime() + : System.currentTimeMillis()); + stmnt.setTimestamp(4, timestamp); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing of artifact failed."); + return; + } + + artifacts.put(artifactId, aId = res[0]); + + storeCollectionItem(collectionId, aId); + + storeData(aId, artifact); + + storeOuts(aId, artifact, context); + } + + + protected void storeCollectionItem( + final Integer collectionId, + final Integer artifactId + ) { + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_COLLECTION_ITEM_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int ciId = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_COLLECTION_ITEM); + stmnt.setInt(1, ciId); + stmnt.setInt(2, collectionId); + stmnt.setInt(3, artifactId); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing of collection item failed."); + } + } + + protected Integer getCollectionId( + final String collectionId, + final Integer ownerId, + final String collectionName, + final Date collectionCreated + ) { + Integer c = getId(collections, collectionId, SQL_COLLECTION_BY_GID); + + if (c != null) { + return c; + } + + final Integer [] res = new Integer[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_COLLECTION_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + res[0] = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_COLLECTION); + stmnt.setInt (1, res[0]); + stmnt.setString(2, collectionId); + stmnt.setInt (3, ownerId); + setString(stmnt, 4, collectionName); + Timestamp timestamp = new Timestamp(collectionCreated != null + ? collectionCreated.getTime() + : System.currentTimeMillis()); + stmnt.setTimestamp(5, timestamp); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (exec.runWrite()) { + collections.put(collectionId, res[0]); + return res[0]; + } + + return null; + } + + protected Integer getUserId(final String userId) { + + Integer u = getId(users, userId, SQL_USER_BY_GID); + + if (u != null) { + return u; + } + + final Integer [] res = new Integer[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_USER_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + res[0] = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_USER); + stmnt.setInt (1, res[0]); + stmnt.setString(2, userId); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (exec.runWrite()) { + users.put(userId, res[0]); + return res[0]; + } + + return null; + } + + public boolean scan(ArtifactDatabase adb) { + log.debug("scan"); + try { + adb.loadAllArtifacts(this); + } + catch (ArtifactDatabaseException ade) { + log.error(ade); + return false; + } + return true; + } + } // class InitialScan + + + public Datacage() { + } + + @Override + public void setup(Document document) { + log.debug("setup"); + DBConfig config = DBConfig.getInstance(); + setupSQL(config.getSQL()); + sqlExecutor = new SQLExecutor(config.getDBConnection()); + } + + protected void setupSQL(SQL sql) { + SQL_DELETE_ALL_USERS = sql.get(SQL_DELETE_ALL_USERS); + SQL_DELETE_ALL_ARTIFACTS = sql.get(SQL_DELETE_ALL_ARTIFACTS); + SQL_USER_ID_NEXTVAL = sql.get(SQL_USER_ID_NEXTVAL); + SQL_USER_BY_GID = sql.get(SQL_USER_BY_GID); + SQL_INSERT_USER = sql.get(SQL_INSERT_USER); + SQL_COLLECTION_BY_GID = sql.get(SQL_COLLECTION_BY_GID); + SQL_COLLECTION_ID_NEXTVAL = sql.get(SQL_COLLECTION_ID_NEXTVAL); + SQL_INSERT_COLLECTION = sql.get(SQL_INSERT_COLLECTION); + SQL_ARTIFACT_BY_GID = sql.get(SQL_ARTIFACT_BY_GID); + SQL_COLLECTION_ITEM_ID_NEXTVAL = + sql.get(SQL_COLLECTION_ITEM_ID_NEXTVAL); + SQL_INSERT_COLLECTION_ITEM = + sql.get(SQL_INSERT_COLLECTION_ITEM); + SQL_ARTIFACT_ID_NEXTVAL = sql.get(SQL_ARTIFACT_ID_NEXTVAL); + SQL_INSERT_ARTIFACT = sql.get(SQL_INSERT_ARTIFACT); + SQL_ARTIFACT_DATA_ID_NEXTVAL = sql.get(SQL_ARTIFACT_DATA_ID_NEXTVAL); + SQL_INSERT_ARTIFACT_DATA = sql.get(SQL_INSERT_ARTIFACT_DATA); + SQL_OUT_ID_NEXTVALUE = sql.get(SQL_OUT_ID_NEXTVALUE); + SQL_INSERT_OUT = sql.get(SQL_INSERT_OUT); + SQL_FACET_ID_NEXTVAL = sql.get(SQL_FACET_ID_NEXTVAL); + SQL_INSERT_FACET = sql.get(SQL_INSERT_FACET); + SQL_UPDATE_COLLECTION_NAME = sql.get(SQL_UPDATE_COLLECTION_NAME); + SQL_DELETE_ARTIFACT_FROM_COLLECTION = + sql.get(SQL_DELETE_ARTIFACT_FROM_COLLECTION); + SQL_DELETE_COLLECTION_BY_GID = sql.get(SQL_DELETE_COLLECTION_BY_GID); + SQL_DELETE_USER_BY_GID = sql.get(SQL_DELETE_USER_BY_GID); + SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID = + sql.get(SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID); + SQL_DELETE_OUTS_BY_ARTIFACT_ID = + sql.get(SQL_DELETE_OUTS_BY_ARTIFACT_ID); + SQL_DELETE_FACETS_BY_ARTIFACT_ID = + sql.get(SQL_DELETE_FACETS_BY_ARTIFACT_ID); + SQL_DELETE_ARTIFACT_BY_GID = + sql.get(SQL_DELETE_ARTIFACT_BY_GID); + } + + protected static final int numFacets(List<Output> outs) { + int sum = 0; + for (Output out: outs) { + sum += out.getFacets().size(); + } + return sum; + } + + protected static final void setString( + PreparedStatement stmnt, + int index, + Object value + ) + throws SQLException + { + if (value == null) { + stmnt.setNull(index, Types.VARCHAR); + } + else { + stmnt.setString(index, value.toString()); + } + } + + @Override + public void systemUp(GlobalContext context) { + log.debug("systemUp entered"); + initialScan(context); + context.put(DATACAGE_KEY, this); + log.debug("systemUp leaved"); + } + + protected void initialScan(GlobalContext context) { + log.debug("initialScan"); + + Object adbObject = context.get(ARTEFACT_DATABASE_KEY); + + if (!(adbObject instanceof ArtifactDatabase)) { + log.error("missing artefact database. Cannot scan"); + return; + } + + ArtifactDatabase adb = (ArtifactDatabase)adbObject; + + if (!cleanDatabase()) { + log.error("cleaning database failed"); + return; + } + + InitialScan is = new InitialScan(context); + + if (!is.scan(adb)) { + log.error("initial scan failed"); + return; + } + + } + + protected boolean cleanDatabase() { + log.debug("cleanDatabase"); + + boolean success = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_ALL_USERS); + stmnt.execute(); + prepareStatement(SQL_DELETE_ALL_ARTIFACTS); + stmnt.execute(); + conn.commit(); + return true; + } + }.runWrite(); + + log.debug("after runWrite(): " + success); + + return success; + } + + + @Override + public void systemDown(GlobalContext context) { + log.debug("systemDown"); + } + + public void setup(GlobalContext globalContext) { + log.debug("setup"); + } + + public void createdArtifact( + Artifact artifact, + Backend backend, + GlobalContext context + ) { + log.debug("createdArtifact"); + + if (artifact == null) { + log.warn("artifact to create is null"); + return; + } + + if (!(artifact instanceof FLYSArtifact)) { + log.warn("need FLYSArtifact here (have " + artifact.getClass() + ")"); + return; + } + + final FLYSArtifact flys = (FLYSArtifact)artifact; + + final int [] res = new int[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_ARTIFACT_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("id generation for artifact failed"); + return false; + } + res[0] = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_ARTIFACT); + stmnt.setInt (1, res[0]); + stmnt.setString (2, flys.identifier()); + stmnt.setString (3, flys.getCurrentStateId()); + stmnt.setTimestamp(4, + new Timestamp(System.currentTimeMillis())); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing of artifact failed."); + return; + } + + storeData(res[0], flys); + storeOuts(res[0], flys, context); + } + + public void storedArtifact( + Artifact artifact, + Backend backend, + GlobalContext context + ) { + log.debug("storedArtifact"); + if (!(artifact instanceof FLYSArtifact)) { + log.warn("need FLYSArtifact here but have a " + artifact.getClass()); + return; + } + + final FLYSArtifact flys = (FLYSArtifact)artifact; + + final Integer [] res = new Integer[1]; + + // check first if artifact already exists + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_ARTIFACT_BY_GID); + stmnt.setString(1, flys.identifier()); + result = stmnt.executeQuery(); + if (!result.next()) { + // new artifact + return true; + } + res[0] = result.getInt(1); + return true; + } + }; + + if (!exec.runRead()) { + log.error("querying artifact failed"); + return; + } + + if (res[0] == null) { // new artifact + createdArtifact(artifact, backend, context); + return; + } + + // artifact already exists -> delete old data + exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_ARTIFACT_DATA_BY_ARTIFACT_ID); + stmnt.setInt(1, res[0]); + stmnt.execute(); + prepareStatement(SQL_DELETE_FACETS_BY_ARTIFACT_ID); + stmnt.setInt(1, res[0]); + stmnt.execute(); + prepareStatement(SQL_DELETE_OUTS_BY_ARTIFACT_ID); + stmnt.setInt(1, res[0]); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("deleting old artifact data failed"); + return; + } + + // write new data + storeData(res[0], flys); + storeOuts(res[0], flys, context); + } + + public void createdUser( + final User user, + Backend backend, + GlobalContext context + ) { + log.debug("createdUser"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_USER_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("id generation for user failed"); + return false; + } + int uId = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_USER); + stmnt.setInt(1, uId); + stmnt.setString(2, user.identifier()); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("create user failed"); + } + } + + public void deletedUser( + final String identifier, + Backend backend, + GlobalContext context + ) { + log.debug("deletedUser"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_USER_BY_GID); + stmnt.setString(1, identifier); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("delete user failed"); + } + } + + public void createdCollection( + final ArtifactCollection collection, + Backend backend, + GlobalContext context + ) { + log.debug("createdCollection"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + String userId = collection.getUser().identifier(); + prepareStatement(SQL_USER_BY_GID); + stmnt.setString(1, userId); + result = stmnt.executeQuery(); + int uId; + if (result.next()) { + uId = result.getInt(1); + reset(); + } + else { + // need to create user first + reset(); + prepareStatement(SQL_USER_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("id generation for user failed"); + return false; + } + uId = result.getInt(1); + reset(); + prepareStatement(SQL_INSERT_USER); + stmnt.setInt(1, uId); + stmnt.setString(2, userId); + stmnt.execute(); + conn.commit(); + reset(); + } + + prepareStatement(SQL_COLLECTION_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("id generation for collection failed"); + return false; + } + int cId = result.getInt(1); + reset(); + + String identifier = collection.identifier(); + String name = collection.getName(); + + prepareStatement(SQL_INSERT_COLLECTION); + stmnt.setInt(1, cId); + stmnt.setString(2, identifier); + stmnt.setInt(3, uId); + setString(stmnt, 4, name); + stmnt.setTimestamp(5, + new Timestamp(System.currentTimeMillis())); + stmnt.execute(); + + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("create collection failed"); + } + } + + public void deletedCollection( + final String identifier, + Backend backend, + GlobalContext context + ) { + log.debug("deletedCollection"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_COLLECTION_BY_GID); + stmnt.setString(1, identifier); + stmnt.execute(); + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("delete collection failed"); + } + } + + public void changedCollectionAttribute( + String identifier, + Document document, + Backend backend, + GlobalContext context + ) { + log.debug("changedCollectionAttribute"); + } + + public void changedCollectionItemAttribute( + String collectionId, + String artifactId, + Document document, + Backend backend, + GlobalContext context + ) { + log.debug("changedCollectionItemAttribute"); + } + + public void addedArtifactToCollection( + final String artifactId, + final String collectionId, + Backend backend, + GlobalContext context + ) { + log.debug("addedArtifactToCollection"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_ARTIFACT_BY_GID); + stmnt.setString(1, artifactId); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int aId = result.getInt(1); + reset(); + + prepareStatement(SQL_COLLECTION_BY_GID); + stmnt.setString(1, collectionId); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int cId = result.getInt(1); + reset(); + + prepareStatement(SQL_COLLECTION_ITEM_ID_NEXTVAL); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int ciId = result.getInt(1); + reset(); + + prepareStatement(SQL_INSERT_COLLECTION_ITEM); + stmnt.setInt(1, ciId); + stmnt.setInt(2, cId); + stmnt.setInt(3, aId); + stmnt.execute(); + + conn.commit(); + return true; + } + }; + if (!exec.runWrite()) { + log.error("added artifact to collection failed"); + } + } + + public void removedArtifactFromCollection( + final String artifactId, + final String collectionId, + Backend backend, + GlobalContext context + ) { + log.debug("removedArtifactFromCollection"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_ARTIFACT_BY_GID); + stmnt.setString(1, artifactId); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int aId = result.getInt(1); + reset(); + prepareStatement(SQL_COLLECTION_BY_GID); + stmnt.setString(1, collectionId); + result = stmnt.executeQuery(); + if (!result.next()) { + return false; + } + int cId = result.getInt(1); + reset(); + prepareStatement(SQL_DELETE_ARTIFACT_FROM_COLLECTION); + stmnt.setInt(1, cId); + stmnt.setInt(2, aId); + stmnt.execute(); + conn.commit(); + return true; + } + }; + if (!exec.runWrite()) { + log.error("removing artifact from collection failed"); + } + } + + public void setCollectionName( + final String collectionId, + final String name, + GlobalContext context + ) { + log.debug("setCollectionName"); + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_UPDATE_COLLECTION_NAME); + stmnt.setString(1, name); + stmnt.setString(2, collectionId); + stmnt.execute(); + conn.commit(); + return true; + } + }; + if (!exec.runWrite()) { + log.error("changing name failed"); + } + } + + protected void storeData( + final int artifactId, + FLYSArtifact artifact + ) { + final Collection<StateData> data = artifact.getAllData(); + + if (data.isEmpty()) { + return; + } + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + int [] ids = new int[data.size()]; + prepareStatement(SQL_ARTIFACT_DATA_ID_NEXTVAL); + + for (int i = 0; i < ids.length; ++i) { + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("generating id for artifact data failed"); + return false; + } + ids[i] = result.getInt(1); + result.close(); result = null; + } + reset(); + prepareStatement(SQL_INSERT_ARTIFACT_DATA); + + int i = 0; + for (StateData sd: data) { + int id = ids[i++]; + stmnt.setInt(1, id); + stmnt.setInt(2, artifactId); + // XXX: Where come the nulls from? + String type = sd.getType(); + if (type == null) type = "String"; + stmnt.setString(3, type); + stmnt.setString(4, sd.getName()); + setString(stmnt, 5, sd.getValue()); + stmnt.execute(); + } + + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing artifact data failed"); + } + } + + protected void storeOuts( + final int artifactId, + final FLYSArtifact artifact, + GlobalContext context + ) { + final List<Output> outs = artifact.getOutputs(context); + + if (outs.isEmpty()) { + return; + } + + final int [] outIds = new int[outs.size()]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_OUT_ID_NEXTVALUE); + for (int i = 0; i < outIds.length; ++i) { + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("generation of out ids failed"); + return false; + } + outIds[i] = result.getInt(1); + result.close(); result = null; + } + reset(); + prepareStatement(SQL_INSERT_OUT); + for (int i = 0; i < outIds.length; ++i) { + Output out = outs.get(i); + stmnt.setInt(1, outIds[i]); + stmnt.setInt(2, artifactId); + stmnt.setString(3, out.getName()); + setString(stmnt, 4, out.getDescription()); + setString(stmnt, 5, out.getType()); + stmnt.execute(); + } + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing artifact outs failed"); + return; + } + + final int FACETS = numFacets(outs); + + if (FACETS == 0) { + return; + } + + exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + int [] facetIds = new int[FACETS]; + prepareStatement(SQL_FACET_ID_NEXTVAL); + for (int i = 0; i < facetIds.length; ++i) { + result = stmnt.executeQuery(); + if (!result.next()) { + log.error("generation of facet ids failed"); + return false; + } + facetIds[i] = result.getInt(1); + result.close(); result = null; + } + reset(); + prepareStatement(SQL_INSERT_FACET); + int index = 0; + for (int i = 0, N = outs.size(); i < N; ++i) { + Output out = outs.get(i); + int outId = outIds[i]; + for (Facet facet: out.getFacets()) { + stmnt.setInt(1, facetIds[index]); + stmnt.setInt(2, outId); + stmnt.setString(3, facet.getName()); + stmnt.setInt(4, facet.getIndex()); + stmnt.setString(5, "XXX"); // TODO: handle states + setString(stmnt, 6, facet.getDescription()); + stmnt.execute(); + ++index; + } + } + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("storing facets failed"); + } + } + + public void killedCollections( + final List<String> identifiers, + GlobalContext context + ) { + log.debug("killedCollections"); + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_COLLECTION_BY_GID); + for (String identifier: identifiers) { + stmnt.setString(1, identifier); + stmnt.execute(); + } + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("killing collections failed"); + } + } + + public void killedArtifacts( + final List<String> identifiers, + GlobalContext context + ) { + log.debug("killedArtifacts"); + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override + public boolean doIt() throws SQLException { + prepareStatement(SQL_DELETE_ARTIFACT_BY_GID); + for (String identifier: identifiers) { + stmnt.setString(1, identifier); + stmnt.execute(); + } + conn.commit(); + return true; + } + }; + + if (!exec.runWrite()) { + log.error("killing artifacts failed"); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,191 @@ +package de.intevation.flys.artifacts.datacage; + +import java.util.List; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactCollection; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.User; + +import de.intevation.artifactdatabase.BackendListener; +import de.intevation.artifactdatabase.Backend; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +/** Triggers Datacage to update db. */ +public class DatacageBackendListener +implements BackendListener +{ + private static Logger log = + Logger.getLogger(DatacageBackendListener.class); + + protected GlobalContext context; + + public DatacageBackendListener() { + log.debug("new DatacageBackendListener"); + } + + protected Datacage getDatacage() { + Object listener = context.get(Datacage.DATACAGE_KEY); + return listener instanceof Datacage + ? (Datacage)listener + : null; + } + + @Override + public void setup(GlobalContext context) { + log.debug("setup"); + this.context = context; + Datacage l = getDatacage(); + if (l != null) { + l.setup(context); + } + } + + @Override + public void createdArtifact(Artifact artifact, Backend backend) { + log.debug("createdArtifact"); + Datacage l = getDatacage(); + if (l != null) { + l.createdArtifact(artifact, backend, context); + } + } + + @Override + public void storedArtifact(Artifact artifact, Backend backend) { + log.debug("storedArtifact"); + Datacage l = getDatacage(); + if (l != null) { + l.storedArtifact(artifact, backend, context); + } + } + + @Override + public void createdUser(User user, Backend backend) { + log.debug("createdUser"); + Datacage l = getDatacage(); + if (l != null) { + l.createdUser(user, backend, context); + } + } + + @Override + public void deletedUser(String identifier, Backend backend) { + log.debug("deletedUser"); + Datacage l = getDatacage(); + if (l != null) { + l.deletedUser(identifier, backend, context); + } + } + + @Override + public void createdCollection( + ArtifactCollection collection, + Backend backend + ) { + log.debug("createdCollection"); + Datacage l = getDatacage(); + if (l != null) { + l.createdCollection(collection, backend, context); + } + } + + @Override + public void deletedCollection(String identifier, Backend backend) { + log.debug("deletedCollection"); + Datacage l = getDatacage(); + if (l != null) { + l.deletedCollection(identifier, backend, context); + } + } + + @Override + public void changedCollectionAttribute( + String identifier, + Document document, + Backend backend + ) { + log.debug("changedCollectionAttribute"); + Datacage l = getDatacage(); + if (l != null) { + l.changedCollectionAttribute( + identifier, document, backend, context); + } + } + + @Override + public void changedCollectionItemAttribute( + String collectionId, + String artifactId, + Document document, + Backend backend + ) { + log.debug("changedCollectionItemAttribute"); + Datacage l = getDatacage(); + if (l != null) { + l.changedCollectionItemAttribute( + collectionId, artifactId, document, backend, context); + } + } + + @Override + public void addedArtifactToCollection( + String artifactId, + String collectionId, + Backend backend + ) { + log.debug("addedArtifactToCollection"); + Datacage l = getDatacage(); + if (l != null) { + l.addedArtifactToCollection( + artifactId, collectionId, backend, context); + } + } + + @Override + public void removedArtifactFromCollection( + String artifactId, + String collectionId, + Backend backend + ) { + log.debug("removedArtifactFromCollection"); + Datacage l = getDatacage(); + if (l != null) { + l.removedArtifactFromCollection( + artifactId, collectionId, backend, context); + } + } + + @Override + public void setCollectionName( + String collectionId, + String name + ) { + log.debug("setCollectionName"); + Datacage l = getDatacage(); + if (l != null) { + l.setCollectionName(collectionId, name, context); + } + } + + @Override + public void killedCollections(List<String> identifiers, Backend backend) { + log.debug("killedCollections"); + Datacage l = getDatacage(); + if (l != null) { + l.killedCollections(identifiers, context); + } + } + + @Override + public void killedArtifacts(List<String> identifiers, Backend backend) { + log.debug("killedArtifacts"); + Datacage l = getDatacage(); + if (l != null) { + l.killedArtifacts(identifiers, context); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,306 @@ +package de.intevation.flys.artifacts.datacage; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +import java.io.InputStream; +import java.io.IOException; +import java.io.File; + +import java.io.FileInputStream; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import org.hibernate.Session; + +import org.hibernate.jdbc.Work; + +import de.intevation.artifacts.common.utils.Config; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.StringUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.backend.SessionHolder; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.datacage.templating.Builder; + + +/** + * Also accessible as Singleton with getInstance(). + */ +public class Recommendations +{ + private static Logger log = Logger.getLogger(Recommendations.class); + + private static final boolean DEVELOPMENT_MODE = + Boolean.getBoolean("flys.datacage.recommendations.development"); + + public static final String XPATH_TEMPLATE = + "/artifact-database/metadata/template/text()"; + + public static final String DEFAULT_TEMPLATE_PATH = + "${artifacts.config.dir}/meta-data.xml"; + + private static Recommendations INSTANCE; + + public static class BuilderProvider + { + protected Builder builder; + + public BuilderProvider() { + } + + public BuilderProvider(Builder builder) { + this.builder = builder; + } + + public Builder getBuilder() { + return builder; + } + } // class BuilderProvider + + public static class FileBuilderProvider + extends BuilderProvider + { + protected File file; + protected long lastModified; + + public FileBuilderProvider() { + } + + public FileBuilderProvider(File file) { + this.file = file; + lastModified = Long.MIN_VALUE; + } + + @Override + public synchronized Builder getBuilder() { + long modified = file.lastModified(); + if (modified > lastModified) { + lastModified = modified; + try { + Document template = loadTemplate(file); + builder = new Builder(template); + } + catch (IOException ioe) { + log.error(ioe); + } + } + return builder; + } + + public BuilderProvider toStaticProvider() { + return new BuilderProvider(builder); + } + } // class BuilderProvider + + protected BuilderProvider builderProvider; + + public Recommendations() { + } + + public Recommendations(BuilderProvider builderProvider) { + this.builderProvider = builderProvider; + } + + public Builder getBuilder() { + return builderProvider.getBuilder(); + } + + protected static void artifactToParameters( + FLYSArtifact artifact, + Map<String, Object> parameters + ) { + parameters.put("CURRENT-STATE-ID", artifact.getCurrentStateId()); + parameters.put("ARTIFACT-ID", artifact.identifier()); + + for (StateData sd: artifact.getAllData()) { + Object value = sd.getValue(); + if (value == null) { + continue; + } + String key = sd.getName().replace('.', '-').toUpperCase(); + parameters.put(key, value); + } + } + + public static void convertKeysToUpperCase( + Map<String, Object> src, + Map<String, Object> dst + ) { + for (Map.Entry<String, Object> entry: src.entrySet()) { + dst.put(entry.getKey().toUpperCase(), entry.getValue()); + } + } + + + /** + * Append recommendations to \param result. + */ + public void recommend( + FLYSArtifact artifact, + String userId, + String [] outs, + Map<String, Object> extraParameters, + Node result + ) { + Map<String, Object> parameters = new HashMap<String, Object>(); + + if (extraParameters != null) { + convertKeysToUpperCase(extraParameters, parameters); + } + + if (userId != null) { + parameters.put("USER-ID", userId); + } + + if (artifact != null) { + artifactToParameters(artifact, parameters); + } + + parameters.put("ARTIFACT-OUTS", StringUtils.toUpperCase(outs)); + + parameters.put("PARAMETERS", parameters); + + recommend(parameters, userId, result); + } + + + /** + * Append recommendations to \param result. + */ + public void recommend( + Map<String, Object> parameters, + String userId, + Node result + ) { + recommend(parameters, userId, result, SessionHolder.HOLDER.get()); + } + + public void recommend( + final Map<String, Object> parameters, + final String userId, + final Node result, + Session session + ) { + session.doWork(new Work() { + @Override + public void execute(Connection systemConnection) + throws SQLException + { + List<Builder.NamedConnection> connections = + new ArrayList<Builder.NamedConnection>(2); + + Connection userConnection = userId != null + ? DBConfig + .getInstance() + .getDBConnection() + .getDataSource() + .getConnection() + : null; + + try { + if (userConnection != null) { + connections.add(new Builder.NamedConnection( + Builder.CONNECTION_USER, userConnection, false)); + } + + connections.add(new Builder.NamedConnection( + Builder.CONNECTION_SYSTEM, systemConnection, true)); + + getBuilder().build(connections, result, parameters); + } + finally { + if (userConnection != null) { + userConnection.close(); + } + } + } + }); + } + + + /** Get singleton instance. */ + public static synchronized Recommendations getInstance() { + if (INSTANCE == null) { + INSTANCE = createRecommendations(); + } + return INSTANCE; + } + + + protected static Document loadTemplate(File file) throws IOException { + InputStream in = null; + + try { + in = new FileInputStream(file); + + Document template = XMLUtils.parseDocument(in); + + if (template == null) { + throw new IOException("cannot load template"); + } + return template; + } + finally { + if (in != null) { + try { + in.close(); + } + catch (IOException ioe) { + log.error(ioe); + } + } + } + } + + public static Recommendations createRecommendations(File file) { + log.debug("Recommendations.createBuilder"); + + if (!file.isFile() || !file.canRead()) { + log.error("Cannot open template file '" + file + "'"); + return null; + } + + FileBuilderProvider fbp = new FileBuilderProvider(file); + + if (fbp.getBuilder() == null) { + log.error("failed loading builder"); + return null; + } + + BuilderProvider bp = DEVELOPMENT_MODE + ? fbp + : fbp.toStaticProvider(); + + return new Recommendations(bp); + } + + protected static Recommendations createRecommendations() { + log.debug("Recommendations.createRecommendations"); + + String path = Config.getStringXPath(XPATH_TEMPLATE); + + if (path == null) { + path = DEFAULT_TEMPLATE_PATH; + } + + path = Config.replaceConfigDir(path); + + log.info("Meta data template: " + path); + + return createRecommendations(new File(path)); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/App.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,109 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.util.Map; +import java.util.HashMap; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.File; +import java.io.FileOutputStream; + +import de.intevation.flys.backend.SessionFactoryProvider; + +import org.hibernate.Session; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.datacage.Recommendations; + +public class App +{ + private static Logger log = Logger.getLogger(App.class); + + public static final String template = + System.getProperty("meta.data.template", "meta-data.xml"); + + public static final String userId = + System.getProperty("user.id"); + + public static final String PARAMETERS = + System.getProperty("meta.data.parameters", ""); + + public static final String OUTPUT = + System.getProperty("meta.data.output"); + + public static Map<String, Object> getParameters() { + HashMap<String, Object> map = new HashMap<String, Object>(); + String [] parts = PARAMETERS.split("\\s*;\\s*"); + for (String part: parts) { + String [] kv = part.split("\\s*:\\s*"); + if (kv.length < 2 || (kv[0] = kv[0].trim()).length() == 0) { + continue; + } + String [] values = kv[1].split("\\s*,\\s*"); + map.put(kv[0], values.length == 1 ? values[0] : values); + } + return map; + } + + public static void main(String [] args) { + + Recommendations rec = Recommendations.createRecommendations( + new File(template)); + + if (rec == null) { + System.err.println("No recommendations created"); + return; + } + + final Document result = XMLUtils.newDocument(); + + final Map<String, Object> parameters = getParameters(); + + Session session = SessionFactoryProvider + .createSessionFactory() + .openSession(); + + try { + rec.recommend(parameters, userId, result, session); + } + finally { + session.close(); + } + + OutputStream out; + + if (OUTPUT == null) { + out = System.out; + } + else { + try { + out = new FileOutputStream(OUTPUT); + } + catch (IOException ioe) { + log.error(ioe); + return; + } + } + + try { + XMLUtils.toStream(result, out); + } + finally { + if (OUTPUT != null) { + try { + out.close(); + } + catch (IOException ioe) { + log.error(ioe); + } + } + } + System.exit(0); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,617 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Deque; +import java.util.ArrayDeque; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.w3c.dom.Node; +import org.w3c.dom.Element; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathConstants; + +import java.sql.SQLException; +import java.sql.Connection; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.utils.Pair; + +import org.apache.log4j.Logger; + +public class Builder +{ + private static Logger log = Logger.getLogger(Builder.class); + + public static final String CONNECTION_USER = "user"; + public static final String CONNECTION_SYSTEM = "system"; + public static final String DEFAULT_CONNECTION_NAME = CONNECTION_SYSTEM; + + public static final Pattern STRIP_LINE_INDENT = + Pattern.compile("\\s*\\r?\\n\\s*"); + + public static final String DC_NAMESPACE_URI = + "http://www.intevation.org/2011/Datacage"; + + private static final Document EVAL_DOCUMENT = + XMLUtils.newDocument(); + + private static final XPathFactory XPATH_FACTORY = + XPathFactory.newInstance(); + + protected Document template; + + protected Map<String, CompiledStatement> compiledStatements; + + public static class NamedConnection { + + protected String name; + protected Connection connection; + protected boolean cached; + + public NamedConnection() { + } + + public NamedConnection( + String name, + Connection connection + ) { + this(name, connection, true); + } + + public NamedConnection( + String name, + Connection connection, + boolean cached + ) { + this.name = name; + this.connection = connection; + this.cached = cached; + } + } // class NamedConnection + + + public class BuildHelper + { + protected Node output; + protected Document owner; + protected StackFrames frames; + protected List<NamedConnection> connections; + protected Map<String, CompiledStatement.Instance> statements; + protected Deque<Pair<NamedConnection, ResultData>> connectionsStack; + + public BuildHelper( + Node output, + List<NamedConnection> connections, + Map<String, Object> parameters + ) { + if (connections.isEmpty()) { + throw new IllegalArgumentException("no connections given."); + } + + this.connections = connections; + connectionsStack = + new ArrayDeque<Pair<NamedConnection, ResultData>>(); + this.output = output; + frames = new StackFrames(parameters); + owner = getOwnerDocument(output); + statements = + new HashMap<String, CompiledStatement.Instance>(); + } + + public void build() throws SQLException { + try { + synchronized (template) { + for (Node current: rootsToList()) { + build(output, current); + } + } + } + finally { + closeStatements(); + } + } + + protected void closeStatements() { + for (CompiledStatement.Instance csi: statements.values()) { + csi.close(); + } + statements.clear(); + } + + /** + * Handle a \<context\> node. + */ + protected void context(Node parent, Element current) + throws SQLException + { + log.debug("dc:context"); + + NodeList subs = current.getChildNodes(); + int S = subs.getLength(); + + // Check only direct children. + Node stmntNode = null; + for (int i = 0; i < S; ++i) { + Node node = subs.item(i); + String ns; + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("statement") + && (ns = node.getNamespaceURI()) != null + && ns.equals(DC_NAMESPACE_URI)) { + stmntNode = node; + break; + } + } + + if (stmntNode == null) { + log.warn("dc:context: cannot find statement"); + return; + } + + String stmntText = stmntNode.getTextContent(); + + String con = current.getAttribute("connection"); + + String key = con + "-" + stmntText; + + CompiledStatement.Instance csi = statements.get(key); + + if (csi == null) { + CompiledStatement cs = compiledStatements.get(stmntText); + csi = cs.new Instance(); + statements.put(key, csi); + } + + NamedConnection connection = connectionsStack.isEmpty() + ? connections.get(0) + : connectionsStack.peek().getA(); + + if (con.length() > 0) { + for (NamedConnection nc: connections) { + if (con.equals(nc.name)) { + connection = nc; + break; + } + } + } + + ResultData rd = csi.execute( + connection.connection, + frames, + connection.cached); + + // only descent if there are results + if (!rd.isEmpty()) { + connectionsStack.push(new Pair(connection, rd)); + try { + for (int i = 0; i < S; ++i) { + build(parent, subs.item(i)); + } + } + finally { + connectionsStack.pop(); + } + } + } + + /** + * Kind of foreach over results of a statement within a context. + */ + protected void elements(Node parent, Element current) + throws SQLException + { + log.debug("dc:elements"); + + if (connectionsStack.isEmpty()) { + log.warn("dc:elements without having results"); + return; + } + + NodeList subs = current.getChildNodes(); + int S = subs.getLength(); + + if (S == 0) { + log.debug("dc:elements has no children"); + return; + } + + ResultData rd = connectionsStack.peek().getB(); + + String [] columns = rd.getColumnLabels(); + + //if (log.isDebugEnabled()) { + // log.debug("pushing vars: " + // + java.util.Arrays.toString(columns)); + //} + + for (Object [] row: rd.getRows()) { + frames.enter(); + try { + frames.put(columns, row); + //if (log.isDebugEnabled()) { + // log.debug("current vars: " + frames.dump()); + //} + for (int i = 0; i < S; ++i) { + build(parent, subs.item(i)); + } + } + finally { + frames.leave(); + } + } + } + + /** + * Create element. + */ + protected void element(Node parent, Element current) + throws SQLException + { + String attr = expand(current.getAttribute("name")); + + if (log.isDebugEnabled()) { + log.debug("dc:element -> '" + attr + "'"); + } + + if (attr.length() == 0) { + log.warn("no name attribute found"); + return; + } + + Element element = owner.createElement(attr); + + NodeList children = current.getChildNodes(); + for (int i = 0, N = children.getLength(); i < N; ++i) { + build(element, children.item(i)); + } + + parent.appendChild(element); + } + + protected void text(Node parent, Element current) + throws SQLException + { + log.debug("dc:text"); + String value = expand(current.getTextContent()); + parent.appendChild(owner.createTextNode(value)); + } + + /** + * Add attribute to an element + * @see Element + */ + protected void attribute(Node parent, Element current) { + + if (parent.getNodeType() != Node.ELEMENT_NODE) { + log.warn("need element here"); + return; + } + + String name = expand(current.getAttribute("name")); + String value = expand(current.getAttribute("value")); + + Element element = (Element)parent; + + element.setAttribute(name, value); + } + + protected void callMacro(Node parent, Element current) + throws SQLException + { + String name = current.getAttribute("name"); + + if (name.length() == 0) { + log.warn("missing 'name' attribute in 'call-macro'"); + return; + } + + NodeList macros = template.getElementsByTagNameNS( + DC_NAMESPACE_URI, "macro"); + + for (int i = 0, N = macros.getLength(); i < N; ++i) { + Element macro = (Element) macros.item(i); + if (name.equals(macro.getAttribute("name"))) { + NodeList subs = macro.getChildNodes(); + for (int j = 0, M = subs.getLength(); j < M; ++j) { + build(parent, subs.item(j)); + } + return; + } + } + + log.warn("no macro '" + name + "' found."); + } + + protected void ifClause(Node parent, Element current) + throws SQLException + { + String test = current.getAttribute("test"); + + if (test.length() == 0) { + log.warn("missing 'test' attribute in 'if'"); + return; + } + + Boolean result = evaluateXPath(test); + + if (result != null && result.booleanValue()) { + NodeList subs = current.getChildNodes(); + for (int i = 0, N = subs.getLength(); i < N; ++i) { + build(parent, subs.item(i)); + } + } + } + + protected void choose(Node parent, Element current) + throws SQLException + { + Node branch = null; + + NodeList children = current.getChildNodes(); + for (int i = 0, N = children.getLength(); i < N; ++i) { + Node child = children.item(i); + String ns = child.getNamespaceURI(); + if (ns == null + || !ns.equals(DC_NAMESPACE_URI) + || child.getNodeType() != Node.ELEMENT_NODE + ) { + continue; + } + String name = child.getLocalName(); + if ("when".equals(name)) { + Element when = (Element)child; + String test = when.getAttribute("test"); + if (test.length() == 0) { + log.warn("no 'test' attribute found for when"); + continue; + } + + Boolean result = evaluateXPath(test); + if (result != null && result.booleanValue()) { + branch = child; + break; + } + + continue; + } + else if ("otherwise".equals(name)) { + branch = child; + // No break here. + } + } + + if (branch != null) { + NodeList subs = branch.getChildNodes(); + for (int i = 0, N = subs.getLength(); i < N; ++i) { + build(parent, subs.item(i)); + } + } + } + + protected Boolean evaluateXPath(String expr) { + + if (log.isDebugEnabled()) { + log.debug("evaluate: '" + expr + "'"); + } + + try { + XPath xpath = XPATH_FACTORY.newXPath(); + xpath.setXPathVariableResolver(frames); + xpath.setXPathFunctionResolver(FunctionResolver.FUNCTIONS); + Object result = xpath.evaluate( + expr, EVAL_DOCUMENT, XPathConstants.BOOLEAN); + + return result instanceof Boolean + ? (Boolean)result + : null; + } + catch (XPathExpressionException xfce) { + log.error("expression: " + expr, xfce); + } + return null; + } + + protected void convert(Node parent, Element current) { + + String variable = expand(current.getAttribute("var")); + String type = expand(current.getAttribute("type")); + + Object [] result = new Object[1]; + + if (frames.getStore(variable, result)) { + Object object = TypeConverter.convert(result[0], type); + frames.put(variable.toUpperCase(), object); + } + } + + protected String expand(String s) { + Matcher m = CompiledStatement.VAR.matcher(s); + + Object [] result = new Object[1]; + + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String key = m.group(1); + result[0] = null; + if (frames.getStore(key, result)) { + m.appendReplacement( + sb, result[0] != null ? result[0].toString() : ""); + } + else { + m.appendReplacement(sb, "\\${" + key + "}"); + } + } + m.appendTail(sb); + return sb.toString(); + } + + protected void build(Node parent, Node current) + throws SQLException + { + String ns = current.getNamespaceURI(); + if (ns != null && ns.equals(DC_NAMESPACE_URI)) { + if (current.getNodeType() != Node.ELEMENT_NODE) { + log.warn("need elements here"); + } + else { + String localName = current.getLocalName(); + if ("attribute".equals(localName)) { + attribute(parent, (Element)current); + } + else if ("context".equals(localName)) { + context(parent, (Element)current); + } + else if ("if".equals(localName)) { + ifClause(parent, (Element)current); + } + else if ("choose".equals(localName)) { + choose(parent, (Element)current); + } + else if ("call-macro".equals(localName)) { + callMacro(parent, (Element)current); + } + else if ("macro".equals(localName)) { + // Simply ignore the definition. + } + else if ("element".equals(localName)) { + element(parent, (Element)current); + } + else if ("elements".equals(localName)) { + elements(parent, (Element)current); + } + else if ("text".equals(localName)) { + text(parent, (Element)current); + } + else if ("comment".equals(localName) + || "statement".equals(localName)) { + // ignore comments and statements in output + } + else if ("convert".equals(localName)) { + convert(parent, (Element)current); + } + else { + log.warn("unknown '" + localName + "' -> ignore"); + } + } + return; + } + + if (current.getNodeType() == Node.TEXT_NODE) { + String txt = current.getNodeValue(); + if (txt != null && txt.trim().length() == 0) { + return; + } + } + + Node copy = owner.importNode(current, false); + + NodeList children = current.getChildNodes(); + for (int i = 0, N = children.getLength(); i < N; ++i) { + build(copy, children.item(i)); + } + parent.appendChild(copy); + } + } // class BuildHelper + + + public Builder() { + compiledStatements = new HashMap<String, CompiledStatement>(); + } + + public Builder(Document template) { + this(); + this.template = template; + compileStatements(); + } + + protected void compileStatements() { + + NodeList nodes = template.getElementsByTagNameNS( + DC_NAMESPACE_URI, "statement"); + + for (int i = 0, N = nodes.getLength(); i < N; ++i) { + Element stmntElement = (Element)nodes.item(i); + String stmnt = trimStatement(stmntElement.getTextContent()); + if (stmnt == null || stmnt.length() == 0) { + throw new IllegalArgumentException("found empty statement"); + } + CompiledStatement cs = new CompiledStatement(stmnt); + // For faster lookup store a shortend string into the template. + stmnt = "s" + i; + stmntElement.setTextContent(stmnt); + compiledStatements.put(stmnt, cs); + } + } + + protected List<Node> rootsToList() { + + NodeList roots = template.getElementsByTagNameNS( + DC_NAMESPACE_URI, "template"); + + List<Node> elements = new ArrayList<Node>(); + + for (int i = 0, N = roots.getLength(); i < N; ++i) { + NodeList rootChildren = roots.item(i).getChildNodes(); + for (int j = 0, M = rootChildren.getLength(); j < M; ++j) { + Node child = rootChildren.item(j); + if (child.getNodeType() == Node.ELEMENT_NODE) { + elements.add(child); + } + } + } + + return elements; + } + + protected static final String trimStatement(String stmnt) { + if (stmnt == null) return null; + //XXX: Maybe a bit to radical for multiline strings? + return STRIP_LINE_INDENT.matcher(stmnt.trim()).replaceAll(" "); + } + + protected static Document getOwnerDocument(Node node) { + Document document = node.getOwnerDocument(); + return document != null ? document : (Document)node; + } + + private static final List<NamedConnection> wrap(Connection connection) { + List<NamedConnection> list = new ArrayList<NamedConnection>(1); + list.add(new NamedConnection(DEFAULT_CONNECTION_NAME, connection)); + return list; + } + + public void build( + Connection connection, + Node output, + Map<String, Object> parameters + ) + throws SQLException + { + build(wrap(connection), output, parameters); + } + + public void build( + List<NamedConnection> connections, + Node output, + Map<String, Object> parameters + ) + throws SQLException + { + BuildHelper helper = new BuildHelper(output, connections, parameters); + + helper.build(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,213 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.ArrayList; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Connection; +import java.sql.ResultSet; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import org.apache.log4j.Logger; + +public class CompiledStatement +{ + private static Logger log = Logger.getLogger(CompiledStatement.class); + + public static final String DATACAGE_DB_CACHE = + "datacage.db"; + + public static final Pattern VAR = + Pattern.compile("\\$\\{([a-zA-Z0-9_-]+)\\}"); + + protected String original; + protected String statement; + + protected Map<String, List<Integer>> positions; + + protected int numVars; + + public class Instance { + + protected PreparedStatement preparedStatement; + + public Instance() { + } + + protected ResultData executeCached( + Cache cache, + Connection connection, + StackFrames frames + ) + throws SQLException + { + log.debug("executeCached"); + Object [] values = new Object[numVars]; + + StringBuilder sb = new StringBuilder(original); + + for (Map.Entry<String, List<Integer>> entry: positions.entrySet()) { + String key = entry.getKey(); + Object value = frames.get(key); + sb.append(';').append(key).append(':').append(value); + for (Integer index: entry.getValue()) { + values[index] = value; + } + } + + // XXX: Maybe too many collisions? + // String key = original + Arrays.hashCode(values); + String key = sb.toString(); + + Element element = cache.get(key); + + if (element != null) { + return (ResultData)element.getValue(); + } + + if (preparedStatement == null) { + preparedStatement = connection.prepareStatement(statement); + } + + for (int i = 0; i < values.length; ++i) { + preparedStatement.setObject(i+1, values[i]); + } + + ResultData data; + + if (log.isDebugEnabled()) { + log.debug("executing: " + statement); + } + + ResultSet result = preparedStatement.executeQuery(); + try { + data = new ResultData(preparedStatement.getMetaData()) + .addAll(result); + } + finally { + result.close(); + } + + element = new Element(key, data); + cache.put(element); + + return data; + } + + protected ResultData executeUncached( + Connection connection, + StackFrames frames + ) + throws SQLException + { + log.debug("executeUncached"); + if (preparedStatement == null) { + if (log.isDebugEnabled()) { + log.debug("preparing statement: " + statement); + } + preparedStatement = connection.prepareStatement(statement); + } + + for (Map.Entry<String, List<Integer>> entry: positions.entrySet()) { + Object value = frames.get(entry.getKey()); + for (Integer index: entry.getValue()) { + preparedStatement.setObject(index+1, value); + } + } + + if (log.isDebugEnabled()) { + log.debug("executing: " + statement); + } + + ResultSet result = preparedStatement.executeQuery(); + try { + return new ResultData(preparedStatement.getMetaData()) + .addAll(result); + } + finally { + result.close(); + } + } + + public ResultData execute( + Connection connection, + StackFrames frames, + boolean cached + ) + throws SQLException + { + if (!cached) { + return executeUncached(connection, frames); + } + + Cache cache = CacheFactory.getCache(DATACAGE_DB_CACHE); + + return cache != null + ? executeCached(cache, connection, frames) + : executeUncached(connection, frames); + } + + public void close() { + if (preparedStatement != null) { + try { + preparedStatement.close(); + } + catch (SQLException sqle) { + } + preparedStatement = null; + } + } + } // class Instance + + public CompiledStatement() { + } + + public CompiledStatement(String original) { + this.original = original; + // TreeMap to ensure order + positions = new TreeMap<String, List<Integer>>(); + compile(); + } + + protected void compile() { + + StringBuffer sb = new StringBuffer(); + + Matcher m = VAR.matcher(original); + + int index = 0; + + while (m.find()) { + String key = m.group(1).toUpperCase(); + List<Integer> indices = positions.get(key); + if (indices == null) { + indices = new ArrayList<Integer>(); + positions.put(key, indices); + } + indices.add(index); + m.appendReplacement(sb, "?"); + ++index; + } + + m.appendTail(sb); + + numVars = index; + + statement = sb.toString(); + } + + public String getStatement() { + return statement; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/FunctionResolver.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,109 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.util.List; +import java.util.Collection; +import java.util.Map; +import java.util.ArrayList; + +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; + +import javax.xml.namespace.QName; + +import org.apache.log4j.Logger; + +public class FunctionResolver +implements XPathFunctionResolver +{ + private static Logger log = Logger.getLogger(FunctionResolver.class); + + public static final String FUNCTION_NAMESPACE_URI = "dc"; + + public static final class Entry { + + String name; + XPathFunction function; + int arity; + + public Entry() { + } + + public Entry(String name, XPathFunction function, int arity) { + this.name = name; + this.function = function; + this.arity = arity; + } + } // class Entry + + public static final FunctionResolver FUNCTIONS = new FunctionResolver(); + + static { + /** Implementation of case-ignoring dc:contains. */ + FUNCTIONS.addFunction("contains", 2, new XPathFunction() { + @Override + public Object evaluate(List args) throws XPathFunctionException { + Object haystack = args.get(0); + Object needle = args.get(1); + + if (needle instanceof String) { + needle = ((String)needle).toUpperCase(); + } + + try { + if (haystack instanceof Collection) { + return Boolean.valueOf( + ((Collection)haystack).contains(needle)); + } + + if (haystack instanceof Map) { + return Boolean.valueOf( + ((Map)haystack).containsKey(needle)); + } + + if (haystack instanceof Object []) { + for (Object straw: (Object [])haystack) { + if (straw.equals(needle)) { + return Boolean.TRUE; + } + } + } + + return Boolean.FALSE; + } + catch (Exception e) { + log.error(e); + throw new XPathFunctionException(e); + } + } + }); + } + + protected List<Entry> functions; + + public FunctionResolver() { + functions = new ArrayList<Entry>(); + } + + public void addFunction(String name, int arity, XPathFunction function) { + functions.add(new Entry(name, function, arity)); + } + + @Override + public XPathFunction resolveFunction(QName functionName, int arity) { + + if (!functionName.getNamespaceURI().equals(FUNCTION_NAMESPACE_URI)) { + return null; + } + + String name = functionName.getLocalPart(); + for (Entry entry: functions) { + if (entry.arity == arity && entry.name.equals(name)) { + return entry.function; + } + } + + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/ResultData.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,77 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.io.Serializable; + +import java.sql.ResultSetMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +public class ResultData +implements Serializable +{ + private static Logger log = Logger.getLogger(ResultData.class); + + protected String [] columns; + + protected List<Object []> rows; + + public ResultData() { + rows = new ArrayList<Object []>(); + } + + public ResultData(ResultSetMetaData meta) + throws SQLException + { + this(); + + boolean debug = log.isDebugEnabled(); + + int N = meta.getColumnCount(); + + columns = new String[N]; + + if (debug) { + log.debug("ResultSet column names:"); + } + + for (int i = 1; i <= N; ++i) { + columns[i-1] = meta.getColumnLabel(i).toUpperCase(); + if (debug) { + log.debug(" " + i + ": " + columns[i-1]); + } + } + } + + public String [] getColumnLabels() { + return columns; + } + + public ResultData addAll(ResultSet result) throws SQLException { + while (result.next()) { + add(result); + } + return this; + } + + public void add(ResultSet result) throws SQLException { + Object [] row = new Object[columns.length]; + for (int i = 0; i < columns.length; ++i) { + row[i] = result.getObject(i+1); + } + rows.add(row); + } + + public List<Object []> getRows() { + return rows; + } + + public boolean isEmpty() { + return rows.isEmpty(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,133 @@ +package de.intevation.flys.artifacts.datacage.templating; + +import java.util.ArrayList; +import java.util.Map; +import java.util.List; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.xpath.XPathVariableResolver; + +import javax.xml.namespace.QName; + +import org.apache.log4j.Logger; + +public class StackFrames +implements XPathVariableResolver +{ + private static Logger log = Logger.getLogger(StackFrames.class); + + protected List<Map<String, Object>> frames; + + public StackFrames() { + frames = new ArrayList<Map<String, Object>>(); + } + + public StackFrames(Map<String, Object> initialFrame) { + this(); + if (initialFrame != null) { + frames.add(new HashMap<String, Object>(initialFrame)); + } + } + + public void enter() { + frames.add(new HashMap<String, Object>()); + } + + public void leave() { + frames.remove(frames.size()-1); + } + + public void put(String key, Object value) { + int N = frames.size(); + if (N > 0) { + frames.get(N-1).put(key, value); + } + } + + public void put(String [] keys, Object [] values) { + Map<String, Object> top = frames.get(frames.size()-1); + for (int i = 0; i < keys.length; ++i) { + top.put(keys[i], values[i]); + } + } + + public boolean containsKey(String key) { + key = key.toUpperCase(); + for (int i = frames.size()-1; i >= 0; --i) { + if (frames.get(i).containsKey(key)) { + return true; + } + } + return false; + } + + /** + * Get element (variable) key. + * Returns null if not found. + * @param key name to resolve + * @return resolution, null if not found. + */ + public Object get(String key) { + return get(key, null); + } + + public boolean getStore(String key, Object [] result) { + + key = key.toUpperCase(); + + for (int i = frames.size()-1; i >= 0; --i) { + Map<String, Object> frame = frames.get(i); + if (frame.containsKey(key)) { + result[0] = frame.get(key); + return true; + } + } + + return false; + } + + public Object get(String key, Object def) { + + key = key.toUpperCase(); + + for (int i = frames.size()-1; i >= 0; --i) { + Map<String, Object> frame = frames.get(i); + if (frame.containsKey(key)) { + return frame.get(key); + } + } + + return def; + } + + @Override + public Object resolveVariable(QName variableName) { + if (log.isDebugEnabled()) { + log.debug("resolve var: " + variableName); + } + return get(variableName.getLocalPart()); + } + + public String dump() { + StringBuilder sb = new StringBuilder("["); + Set<String> already = new HashSet<String>(); + + boolean first = true; + + for (int i = frames.size()-1; i >= 0; --i) { + Map<String, Object> frame = frames.get(i); + for (Map.Entry<String, Object> entry: frame.entrySet()) { + if (already.add(entry.getKey())) { + if (first) { first = false; } + else { sb.append(", "); } + sb.append('\'').append(entry.getKey()) + .append("'='").append(entry.getValue()).append('\''); + } + } + } + return sb.append(']').toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/TypeConverter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,31 @@ +package de.intevation.flys.artifacts.datacage.templating; + +public class TypeConverter +{ + private TypeConverter() { + } + + public static Object convert(Object object, String type) { + + if (type == null) { + return object; + } + + if ("Integer".equals(type)) { + return Integer.valueOf(object.toString()); + } + + if ("Double".equals(type)) { + return Double.valueOf(object.toString()); + } + + if ("String".equals(type)) { + return object.toString(); + } + + // TODO: Add more types + + return object; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,403 @@ +package de.intevation.flys.artifacts.geom; + +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; + +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + +import de.intevation.flys.artifacts.math.Linear; + +import org.apache.log4j.Logger; + +import gnu.trove.TDoubleArrayList; + +/** + * Utility to create lines (intersect water with cross-section etc). + */ +public class Lines +{ + private static Logger log = Logger.getLogger(Lines.class); + + public static final double EPSILON = 1e-4; + + public static enum Mode { UNDEF, WET, DRY }; + + + /** Never instantiate Lines, use static functions instead. */ + protected Lines() { + } + + + /** + * Calculate area of polygon with four vertices. + * @return area of polygon with four vertices. + */ + public static double area(Point2D p1, Point2D p2, Point2D p3, Point2D p4) { + double[] x = new double[] {p1.getX(), p2.getX(), p3.getX(), p4.getX(), p1.getX() }; + double[] y = new double[] {p1.getY(), p2.getY(), p3.getY(), p4.getY(), p1.getY() }; + double area = 0d; + for (int i=0; i <4; i++) { + area += (x[i] * y[i+1]) - (x[i+1] * y[i]); + } + return Math.abs(area * 0.5d); + } + + + /** + * Calculate the 'length' of the given lines. + * @param lines lines of which to calculate length. + */ + public static double length(List<Line2D> lines) { + double sum = 0d; + for (Line2D line: lines) { + double xDiff = line.getX1() - line.getX2(); + double yDiff = line.getY1() - line.getY2(); + sum += Math.sqrt(xDiff*xDiff + yDiff*yDiff); + } + return sum; + } + + + /** List of lines and a double-precision area. */ + private static class ListWithArea { + public List<Line2D> lines; + public double area; + public ListWithArea(List<Line2D> lines, double area) { + this.lines = lines; + this.area = area; + } + } + + + /** + * For a cross section given as points and a waterlevel (in meters), + * create a set of lines that represent the water surface, assuming it + * is distributed horizontally equally. + * @param points the points describing the river bed. + * @param waterLevel the height of the horizontal water line. + * @return A list of Lines representing the water surface and the + * calculated area between water surface and river bed. + */ + public static ListWithArea fillWater(List<Point2D> points, double waterLevel) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("fillWater"); + log.debug("----------------------------"); + } + + List<Line2D> result = new ArrayList(); + + int N = points.size(); + + if (N == 0) { + return new ListWithArea(result, 0d); + } + + if (N == 1) { + Point2D p = points.get(0); + // Only generate point if over profile + if (waterLevel > p.getY()) { + result.add(new Line2D.Double( + p.getX(), waterLevel, + p.getX(), waterLevel)); + } + // TODO continue calculating area. + return new ListWithArea(result, 0d); + } + + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = -Double.MAX_VALUE; + double maxY = -Double.MAX_VALUE; + + // To ensure for sequences of equals x's that + // the original index order is preserved. + for (Point2D p: points) { + double x = p.getX(), y = p.getY(); + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + + if (minY > waterLevel) { // profile completely over water level + log.debug("complete over water"); + return new ListWithArea(result, 0d); + } + + if (waterLevel > maxY) { // water floods profile + log.debug("complete under water"); + result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); + return new ListWithArea(result, 0d); + } + + // Water is sometimes above, sometimes under profile. + Mode mode = Mode.UNDEF; + + double startX = minX; + + double area = 0d; + // Walking along the profile. + for (int i = 1; i < N; ++i) { + Point2D p1 = points.get(i-1); + Point2D p2 = points.get(i); + + if (p1.getY() < waterLevel && p2.getY() < waterLevel) { + // completely under water + if (debug) { + log.debug("under water: " + p1 + " " + p2); + } + if (mode != Mode.WET) { + startX = p1.getX(); + mode = Mode.WET; + } + area += area(p1, p2, + new Point2D.Double(p2.getX(), waterLevel), + new Point2D.Double(p1.getX(), waterLevel)); + continue; + } + + // TODO trigger area calculation + if (p1.getY() > waterLevel && p2.getY() > waterLevel) { + if (debug) { + log.debug("over water: " + p1 + " " + p2); + } + // completely over water + if (mode == Mode.WET) { + log.debug("over/wet"); + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + } + mode = Mode.DRY; + continue; + } + + // TODO trigger area calculation + if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { + // vertical line + switch (mode) { + case WET: + log.debug("vertical/wet"); + mode = Mode.DRY; + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + break; + case DRY: + log.debug("vertical/dry"); + mode = Mode.WET; + startX = p2.getX(); + break; + default: // UNDEF + log.debug("vertical/undef"); + if (p2.getY() < waterLevel) { + mode = Mode.WET; + startX = p2.getX(); + } + else { + mode = Mode.DRY; + } + } + continue; + } + + // check if waterlevel directly hits the vertices; + + boolean p1W = Math.abs(waterLevel - p1.getY()) < EPSILON; + boolean p2W = Math.abs(waterLevel - p2.getY()) < EPSILON; + + // TODO trigger area calculation + if (p1W || p2W) { + if (debug) { + log.debug("water hits vertex: " + p1 + " " + p2 + " " + mode); + } + if (p1W && p2W) { // parallel to water -> dry + log.debug("water hits both vertices"); + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + } + mode = Mode.DRY; + } + else if (p1W) { // p1 == waterlevel + log.debug("water hits first vertex"); + if (p2.getY() > waterLevel) { // --> dry + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + } + mode = Mode.DRY; + } + else { // --> wet + if (mode != Mode.WET) { + startX = p1.getX(); + mode = Mode.WET; + } + area += area(p1, p2, + new Point2D.Double(p2.getX(), waterLevel), + new Point2D.Double(p2.getX(), waterLevel)); + } + } + else { // p2 == waterlevel + log.debug("water hits second vertex"); + if (p1.getY() > waterLevel) { // --> wet + if (mode != Mode.WET) { + startX = p2.getX(); + mode = Mode.WET; + } + } + else { // --> dry + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + p2.getX(), waterLevel)); + } + mode = Mode.DRY; + area += area(p1, p2, + new Point2D.Double(p1.getX(), waterLevel), + new Point2D.Double(p1.getX(), waterLevel)); + } + } + if (debug) { + log.debug("mode is now: " + mode); + } + continue; + } + + // TODO trigger area calculation + // intersection case + double x = Linear.linear( + waterLevel, + p1.getY(), p2.getY(), + p1.getX(), p2.getX()); + + if (debug) { + log.debug("intersection p1:" + p1); + log.debug("intersection p2:" + p2); + log.debug("intersection at x: " + x); + } + + // Add area of that part of intersection that is 'wet'. + if (p1.getY() > waterLevel) { + area += area(new Point2D.Double(x, waterLevel), + p2, + new Point2D.Double(p2.getX(), waterLevel), + new Point2D.Double(x, waterLevel)); + } + else { + area += area(new Point2D.Double(x, waterLevel), + p1, + new Point2D.Double(p1.getX(), waterLevel), + new Point2D.Double(x, waterLevel)); + } + + switch (mode) { + case WET: + log.debug("intersect/wet"); + mode = Mode.DRY; + result.add(new Line2D.Double( + startX, waterLevel, + x, waterLevel)); + break; + + case DRY: + log.debug("intersect/dry"); + mode = Mode.WET; + startX = x; + break; + + default: // UNDEF + log.debug("intersect/undef"); + if (p2.getY() > waterLevel) { + log.debug("intersect/undef/over"); + mode = Mode.DRY; + result.add(new Line2D.Double( + p1.getX(), waterLevel, + x, waterLevel)); + } + else { + mode = Mode.WET; + startX = x; + } + } // switch mode + } // for all points p[i] and p[i-1] + + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + maxX, waterLevel)); + } + + return new ListWithArea(result, area); + } + + + /** + * Class holding points that form lines and the calculated length. + */ + public static class LineData { + public double [][] points; + public double width; + public double area; + public LineData(double[][] points, double width, double area) { + this.points = points; + this.width = width; + this.area = area; + } + } + + + /** Return length of a single line. */ + public static double lineLength(Line2D line) { + double xDiff = line.getX1() - line.getX2(); + double yDiff = line.getY1() - line.getY2(); + return Math.sqrt(xDiff*xDiff + yDiff*yDiff); + } + + + /** + * @param points the riverbed. + */ + public static LineData createWaterLines( + List<Point2D> points, + double waterlevel + ) { + ListWithArea listAndArea = fillWater(points, waterlevel); + List<Line2D> lines = listAndArea.lines; + + TDoubleArrayList lxs = new TDoubleArrayList(); + TDoubleArrayList lys = new TDoubleArrayList(); + double linesLength = 0.0f; + + for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) { + Line2D line = iter.next(); + Point2D p1 = line.getP1(); + Point2D p2 = line.getP2(); + lxs.add(p1.getX()); + lys.add(p1.getY()); + lxs.add(p2.getX()); + lys.add(p2.getY()); + + // Length calculation. + linesLength += lineLength(line); + + if (iter.hasNext()) { + lxs.add(Double.NaN); + lys.add(Double.NaN); + } + } + + return new LineData( + new double [][] { lxs.toNativeArray(), lys.toNativeArray() }, + linesLength, listAndArea.area + ); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/map/PrintMap.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.artifacts.map; + +import java.awt.Color; +import java.awt.Rectangle; + +import java.io.File; +import java.io.IOException; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +import java.util.List; + +import java.net.URL; +import java.net.MalformedURLException; + +import javax.imageio.ImageIO; + + +import org.geotools.data.ows.Layer; +import org.geotools.data.ows.WMSCapabilities; +import org.geotools.data.wms.WebMapServer; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.map.MapContext; +import org.geotools.map.WMSMapLayer; +import org.geotools.ows.ServiceException; +import org.geotools.renderer.lite.StreamingRenderer; +import org.geotools.renderer.GTRenderer; + + +public class PrintMap { + + public static final String DEFAULT_WMS = "http://map1.naturschutz.rlp.de/service_lanis/mod_wms/wms_getmap.php?mapfile=group_gdide&REQUEST=GetCapabilities&SERVICE=WMS"; + public static final String DEFAULT_OUTFILE = "~/map.jpeg"; + + public static final String MAPSERVER = System.getProperty("wms", DEFAULT_WMS); + public static final String MAP_IMAGE = System.getProperty("outfile", DEFAULT_OUTFILE); + + + public static void main(String[] args) { + System.out.println("-> start PrintMap"); + System.out.println(" -> Print layers of WMS: " + MAPSERVER); + + try { + WebMapServer server = getMapserver(); + WMSMapLayer[] wmsLayer = getWMSLayers(server); + + MapContext mapcontent = new MapContext( wmsLayer ); + mapcontent.setTitle(" NEW MAP CONTENT TITLE "); + + printMap(mapcontent); + } + catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("-> finished PrintMap"); + } + + + public static void printMap(MapContext map) throws Exception { + int imageWidth = 600; + + GTRenderer renderer = new StreamingRenderer(); + renderer.setContext(map); + + Rectangle imageBounds = null; + ReferencedEnvelope mapBounds = null; + + try { + mapBounds = map.getLayerBounds(); + double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0); + imageBounds = new Rectangle( + 0, 0, + imageWidth, + (int) Math.round(imageWidth * heightToWidth)); + + } + catch (Exception e) { + // failed to access map layers + throw new RuntimeException(e); + } + + BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB); + Graphics2D gr = image.createGraphics(); + gr.setPaint(Color.WHITE); + gr.fill(imageBounds); + + try { + renderer.paint(gr, imageBounds, mapBounds); + File fileToSave = new File(MAP_IMAGE); + ImageIO.write(image, "jpeg", fileToSave); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public static WebMapServer getMapserver() throws MalformedURLException, IOException, ServiceException { + return new WebMapServer(getServerUrl()); + } + + + public static URL getServerUrl() throws MalformedURLException { + return new URL(MAPSERVER); + } + + + public static WMSMapLayer[] getWMSLayers(WebMapServer server) { + if (server == null) { + System.out.println("WebMapServer == null"); + throw new RuntimeException("WebMapServer == null"); + } + + WMSCapabilities capabilities = server.getCapabilities(); + + List<Layer> layers = capabilities.getLayerList(); + WMSMapLayer[] wmslayers = new WMSMapLayer[layers.size()]; + + for (int i = 0, L = layers.size(); i < L; i++) { + Layer l = layers.get(i); + + System.out.println(" -> add layer: " + l); + wmslayers[i] = new WMSMapLayer(server, l); + } + + return wmslayers; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/AddScaleFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,19 @@ +package de.intevation.flys.artifacts.math; + +public class AddScaleFunction +implements Function +{ + protected double b; + protected double m; + + public AddScaleFunction(double b, double m) { + this.b = b; + this.m = m; + } + + @Override + public double value(double x) { + return (x + b)*m; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,217 @@ +package de.intevation.flys.artifacts.math; + +import java.util.ArrayList; +import java.util.List; + +import java.io.Serializable; + +import org.apache.commons.math.analysis.interpolation.SplineInterpolator; + +import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; + +import org.apache.commons.math.ArgumentOutsideDomainException; + +import org.apache.commons.math.exception.MathIllegalArgumentException; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.model.Calculation; + +import de.intevation.flys.utils.DoubleUtil; + +public class BackJumpCorrector +implements Serializable +{ + private static Logger log = Logger.getLogger(BackJumpCorrector.class); + + protected ArrayList<Double> backjumps; + + protected double [] corrected; + + public BackJumpCorrector() { + backjumps = new ArrayList<Double>(); + } + + public boolean hasBackJumps() { + return !backjumps.isEmpty(); + } + + public List<Double> getBackJumps() { + return backjumps; + } + + public double [] getCorrected() { + return corrected; + } + + public boolean doCorrection( + double [] km, + double [] ws, + Calculation errors + ) { + boolean wsUp = DoubleUtil.isIncreasing(ws); + + if (wsUp) { + km = DoubleUtil.swapClone(km); + ws = DoubleUtil.swapClone(ws); + } + + boolean kmUp = DoubleUtil.isIncreasing(km); + + if (!kmUp) { + km = DoubleUtil.sumDiffs(km); + } + + if (log.isDebugEnabled()) { + log.debug("BackJumpCorrector.doCorrection ------- enter"); + log.debug(" km increasing: " + DoubleUtil.isIncreasing(km)); + log.debug(" ws increasing: " + DoubleUtil.isIncreasing(ws)); + log.debug("BackJumpCorrector.doCorrection ------- leave"); + } + + boolean hasBackJumps = doCorrectionClean(km, ws, errors); + + if (hasBackJumps && wsUp) { + // mirror back + DoubleUtil.swap(corrected); + } + + return hasBackJumps; + } + + protected boolean doCorrectionClean( + double [] km, + double [] ws, + Calculation errors + ) { + int N = km.length; + + if (N != ws.length) { + throw new IllegalArgumentException("km.length != ws.length"); + } + + if (N < 2) { + return false; + } + + SplineInterpolator interpolator = null; + + for (int i = 1; i < N; ++i) { + if (ws[i] <= ws[i-1]) { + // no back jump + continue; + } + backjumps.add(km[i]); + + if (corrected == null) { + // lazy cloning + ws = corrected = (double [])ws.clone(); + } + + double above = aboveWaterKM(km, ws, i); + + if (Double.isNaN(above)) { // run over start km + // fill all previous + for (int j = 0; j < i; ++j) { + ws[j] = ws[i]; + } + continue; + } + + double distance = Math.abs(km[i] - above); + + double quarterDistance = 0.25*distance; + + double start = above - quarterDistance; + + double startHeight = DoubleUtil.interpolateSorted(km, ws, start); + + if (Double.isNaN(startHeight)) { + // run over start km + startHeight = ws[0]; + } + + double between = above + quarterDistance; + + double aboveHeight = ws[i] + 0.25*(startHeight - ws[i]); + + double [] x = { start, above, between }; + double [] y = { startHeight, aboveHeight, ws[i] }; + + if (log.isDebugEnabled()) { + for (int j = 0; j < x.length; ++j) { + log.debug(" " + x[j] + " -> " + y[j]); + } + } + + if (interpolator == null) { + interpolator = new SplineInterpolator(); + } + + PolynomialSplineFunction spline; + + try { + spline = interpolator.interpolate(x, y); + } + catch (MathIllegalArgumentException miae) { + errors.addProblem("spline.creation.failed"); + log.error(miae); + continue; + } + + try { + if (log.isDebugEnabled()) { + log.debug("spline points:"); + for (int j = 0; j < x.length; ++j) { + log.debug(x[j] + " " + y[j] + " " + spline.value(x[j])); + } + } + + int j = i-1; + + for (; j >= 0 && km[j] >= between; --j) { + ws[j] = ws[i]; + } + + for (; j >= 0 && ws[j] < startHeight; --j) { + ws[j] = spline.value(km[j]); + } + } + catch (ArgumentOutsideDomainException aode) { + errors.addProblem("spline.interpolation.failed"); + log.error("spline interpolation failed", aode); + } + } // for all km + + return !backjumps.isEmpty(); + } + + + protected static double aboveWaterKM( + double [] km, + double [] ws, + int wIndex + ) { + double w = ws[wIndex]; + + while (--wIndex >= 0) { + // still under water + if (ws[wIndex] < w) continue; + + if (ws[wIndex] > w) { + // f(ws[wIndex]) = km[wIndex] + // f(ws[wIndex+1]) = km[wIndex+1] + return Linear.linear( + w, + ws[wIndex], ws[wIndex+1], + km[wIndex], km[wIndex+1]); + } + else { + return km[wIndex]; + } + } + + return Double.NaN; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Distance.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.artifacts.math; + +/** Helper to calculate distance(s). */ +public final class Distance { + /** Return distance between two values. */ + public static double distance(double a, double b) { + return Math.abs(a - b); + } + + /** Return whether a and be are within a certain distance. */ + public static boolean within(double a, double b, double threshold) { + return distance(a, b) <= threshold; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/FilterFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +package de.intevation.flys.artifacts.math; + +public class FilterFunction implements Function { + + protected Function parent; + + public FilterFunction(Function parent) { + this.parent = parent; + } + + @Override + public double value(double x) { + return parent.value(x); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Function.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,6 @@ +package de.intevation.flys.artifacts.math; + +public interface Function { + double value(double x); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Identity.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.artifacts.math; + +public final class Identity +implements Function +{ + public static final Identity IDENTITY = new Identity(); + + public Identity() { + } + + public double value(double x) { + return x; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Linear.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,78 @@ +package de.intevation.flys.artifacts.math; + +public final class Linear +implements Function +{ + private double m; + private double b; + + public Linear( + double x1, double x2, + double y1, double y2 + ) { + // y1 = m*x1 + b + // y2 = m*x2 + b + // y2 - y1 = m*(x2 - x1) + // m = (y2 - y1)/(x2 - x1) # x2 != x1 + // b = y1 - m*x1 + + if (x1 == x2) { + m = 0; + b = 0.5*(y1 + y2); + } + else { + m = (y2 - y1)/(x2 - x1); + b = y1 - m*x1; + } + } + + public static final double linear( + double x, + double x1, double x2, + double y1, double y2 + ) { + // y1 = m*x1 + b + // y2 = m*x2 + b + // y2 - y1 = m*(x2 - x1) + // m = (y2 - y1)/(x2 - x1) # x2 != x1 + // b = y1 - m*x1 + + if (x1 == x2) { + return 0.5*(y1 + y2); + } + double m = (y2 - y1)/(x2 - x1); + double b = y1 - m*x1; + return x*m + b; + } + + @Override + public double value(double x) { + return m*x + b; + } + + public static final double factor(double x, double p1, double p2) { + // 0 = m*p1 + b <=> b = -m*p1 + // 1 = m*p2 + b + // 1 = m*(p2 - p1) + // m = 1/(p2 - p1) # p1 != p2 + // f(x) = x/(p2-p1) - p1/(p2-p1) <=> (x-p1)/(p2-p1) + + return p1 == p2 ? 0.0 : (x-p1)/(p2-p1); + } + + public static final double weight(double factor, double a, double b) { + //return (1.0-factor)*a + factor*b; + return a + factor*(b-a); + } + + public static final void weight( + double factor, + double [] a, double [] b, double [] c + ) { + int N = Math.min(Math.min(a.length, b.length), c.length); + for (int i = 0; i < N; ++i) { + c[i] = weight(factor, a[i], b[i]); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/LinearFilterFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,24 @@ +package de.intevation.flys.artifacts.math; + +public class LinearFilterFunction +extends FilterFunction +{ + protected double m; + protected double b; + + public LinearFilterFunction(double m, double b) { + this(Identity.IDENTITY, m, b); + } + + public LinearFilterFunction(Function parent, double m, double b) { + super(parent); + this.m = m; + this.b = b; + } + + @Override + public double value(double x) { + return super.value(x)*m + b; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/LinearFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,19 @@ +package de.intevation.flys.artifacts.math; + +public class LinearFunction +implements Function +{ + protected double m; + protected double b; + + public LinearFunction(double m, double b) { + this.m = m; + this.b = b; + } + + @Override + public double value(double x) { + return x*m + b; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/NaNFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +package de.intevation.flys.artifacts.math; + +public final class NaNFunction +implements Function +{ + public static final Function INSTANCE = new NaNFunction(); + + private NaNFunction() { + } + + @Override + public double value(double x) { + return Double.NaN; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Outlier.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,107 @@ +package de.intevation.flys.artifacts.math; + +import java.util.List; + +import org.apache.commons.math.MathException; + +import org.apache.commons.math.distribution.TDistributionImpl; + +import org.apache.commons.math.stat.descriptive.moment.Mean; +import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; + +import org.apache.log4j.Logger; + +public class Outlier +{ + public static final double EPSILON = 1e-5; + + public static final double DEFAULT_ALPHA = 0.05; + + private static Logger log = Logger.getLogger(Outlier.class); + + protected Outlier() { + } + + public static Integer findOutlier(List<Double> values) { + return findOutlier(values, DEFAULT_ALPHA); + } + + public static Integer findOutlier(List<Double> values, double alpha) { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("outliers significance: " + alpha); + } + + alpha = 1d - alpha; + + int N = values.size(); + + if (debug) { + log.debug("Values to check: " + N); + } + + if (N < 3) { + return null; + } + + Mean mean = new Mean(); + StandardDeviation std = new StandardDeviation(); + + for (Double value: values) { + double v = value.doubleValue(); + mean.increment(v); + std .increment(v); + } + + double m = mean.getResult(); + double s = std.getResult(); + + if (debug) { + log.debug("mean: " + m); + log.debug("std dev: " + s); + } + + double maxZ = -Double.MAX_VALUE; + int iv = -1; + for (int i = N-1; i >= 0; --i) { + double v = values.get(i).doubleValue(); + double z = Math.abs(v - m); + if (z > maxZ) { + maxZ = z; + iv = i; + } + } + + if (Math.abs(s) < EPSILON) { + return null; + } + + maxZ /= s; + + TDistributionImpl tdist = new TDistributionImpl(N-2); + + double t; + + try { + t = tdist.inverseCumulativeProbability(alpha/(N+N)); + } + catch (MathException me) { + log.error(me); + return null; + } + + t *= t; + + double za = ((N-1)/Math.sqrt(N))*Math.sqrt(t/(N-2d+t)); + + if (debug) { + log.debug("max: " + maxZ + " crit: " + za); + } + + return maxZ > za + ? Integer.valueOf(iv) + : null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Sub.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.artifacts.math; + +public final class Sub +implements Function +{ + private double s; + + public Sub(double s) { + this.s = s; + } + + @Override + public double value(double x) { + return x - s; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/UnivariateRealFunctionFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,34 @@ +package de.intevation.flys.artifacts.math; + +import org.apache.commons.math.FunctionEvaluationException; + +import org.apache.commons.math.analysis.UnivariateRealFunction; + +public final class UnivariateRealFunctionFunction +implements Function +{ + private UnivariateRealFunction function; + + public UnivariateRealFunctionFunction(UnivariateRealFunction function) { + this.function = function; + } + + @Override + public double value(double x) { + try { + return function.value(x); + } + catch (FunctionEvaluationException fee) { + return Double.NaN; + } + } + + public UnivariateRealFunction getFunction() { + return function; + } + + public void setFunction(UnivariateRealFunction function) { + this.function = function; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/WKmsOperation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,148 @@ +package de.intevation.flys.artifacts.math; + +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WKmsImpl; + +import java.util.Arrays; + +public abstract class WKmsOperation +{ + public static final double EPSILON = 1e-6; + + public static final class KmW + implements Comparable<KmW> + { + protected double km; + protected double w; + + public KmW(double km, double w) { + this.km = km; + this.w = w; + } + + public int compareTo(KmW other) { + return km < other.km + ? -1 + : km > other.km ? +1 : 0; + } + + public boolean kmEquals(KmW other) { + return Math.abs(km - other.km) < EPSILON; + } + + public double subtract(KmW other) { + return w - other.w; + } + } // class KmW + + public static final WKmsOperation SUBTRACTION = new WKmsOperation() { + + @Override + public WKms operate(WKms a, WKms b) { + return subtract(a, b); + } + }; + + protected WKmsOperation() { + } + + public abstract WKms operate(WKms a, WKms b); + + /** + * Subtract two series from each other, interpolate values + * missing in one series in the other. + */ + public static WKms subtract(WKms minuend, WKms subtrahend) { + + int M = minuend .size(); + int S = subtrahend.size(); + + // Don't subtract empty sets + if (M < 1 || S < 1) { + return new WKmsImpl(); + } + + KmW [] ms = new KmW[M]; + KmW [] ss = new KmW[S]; + + for (int i = 0; i < M; ++i) { + ms[i] = new KmW(minuend.getKm(i), minuend.getW(i)); + } + + for (int i = 0; i < S; ++i) { + ss[i] = new KmW(subtrahend.getKm(i), subtrahend.getW(i)); + } + + Arrays.sort(ms); + Arrays.sort(ss); + + // no overlap -> empty result set + if (ms[0].km > ss[S-1].km || ss[0].km > ms[M-1].km) { + return new WKmsImpl(); + } + + WKmsImpl result = new WKmsImpl(); + + int mi = 0; + int si = 0; + + OUT: while (mi < M && si < S) { + KmW m = ms[mi]; + KmW s = ss[si]; + + if (m.km + EPSILON < s.km) { + // minuend is before subtrahend + + while (ms[mi].km + EPSILON < s.km) { + if (++mi >= M) { + break OUT; + } + } + + if (ms[mi].km + EPSILON > s.km) { + double mw = Linear.linear( + s.km, + ms[mi-1].km, ms[mi].km, + ms[mi-1].w, ms[mi].w); + result.add(s.km, mw - s.w); + ++si; + } + else { // s.km == ms[mi].km + result.add(s.km, ms[mi].subtract(s)); + ++mi; + ++si; + } + } + else if (m.km > s.km + EPSILON) { + // subtrahend is before minuend + + while (m.km > ss[si].km + EPSILON) { + if (++si >= S) { + break OUT; + } + } + + if (ss[si].km + EPSILON > m.km) { + double sw = Linear.linear( + m.km, + ss[si-1].km, ss[si].km, + ss[si-1].w, ss[si].w); + result.add(m.km, m.w - sw); + } + else { // ss[si].km == m.km + result.add(m.km, m.subtract(ss[si])); + ++mi; + ++si; + } + } + else { // m.km == s.km + result.add(s.km, m.subtract(s)); + ++mi; + ++si; + } + } + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/App.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,127 @@ +package de.intevation.flys.artifacts.math.fitting; + +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.TreeMap; +import java.util.Comparator; + +import java.io.IOException; +import java.io.BufferedReader; +import java.io.Reader; +import java.io.InputStreamReader; + +import org.apache.commons.math.optimization.fitting.CurveFitter; + +import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; + +import org.apache.commons.math.MathException; + +public class App +{ + public static final double EPS = 1e-5; + + public static final String FUNCTION_NAME = + System.getProperty("function", "linear"); + + public static final Comparator<Double> EPS_CMP = + new Comparator<Double>() { + @Override + public int compare(Double a, Double b) { + double diff = a - b; + if (diff < -EPS) return -1; + if (diff > EPS) return +1; + return 0; + } + }; + + public static final List<Double []>readPoints(Reader reader) + throws IOException + { + Map<Double, Double> map = new TreeMap<Double, Double>(EPS_CMP); + + BufferedReader input = new BufferedReader(reader); + + String line; + while ((line = input.readLine()) != null) { + if ((line = line.trim()).length() == 0 || line.startsWith("#")) { + continue; + } + + String [] parts = line.split("\\s+"); + + if (parts.length < 2) { + continue; + } + + try { + Double x = Double.valueOf(parts[0]); + Double y = Double.valueOf(parts[1]); + + Double old = map.put(x, y); + + if (old != null) { + System.err.println("duplicate x: " + x); + } + } + catch (NumberFormatException nfe) { + nfe.printStackTrace(); + } + } + + List<Double []> list = new ArrayList<Double []>(map.size()); + + for (Map.Entry<Double, Double> entry: map.entrySet()) { + list.add(new Double [] { entry.getKey(), entry.getValue() }); + } + + return list; + } + + public static void main(String [] args) { + + Function function = FunctionFactory + .getInstance() + .getFunction(FUNCTION_NAME); + + if (function == null) { + System.err.println("Cannot find function '" + FUNCTION_NAME + "'."); + System.exit(1); + } + + List<Double []> points = null; + + try { + points = readPoints(new InputStreamReader(System.in)); + } + catch (IOException ioe) { + ioe.printStackTrace(); + System.exit(1); + } + + LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer(); + + CurveFitter cf = new CurveFitter(lmo); + + for (Double [] point: points) { + cf.addObservedPoint(point[0], point[1]); + } + + double [] parameters = null; + + try { + parameters = cf.fit(function, function.getInitialGuess()); + } + catch (MathException me) { + me.printStackTrace(); + System.exit(1); + } + + String [] parameterNames = function.getParameterNames(); + + for (int i = 0; i < parameterNames.length; ++i) { + System.err.println(parameterNames[i] + ": " + parameters[i]); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,62 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class Exp +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = a^Q*log(a)*m") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + double m = parameters[0]; + final double a = parameters[1]; + final double logam = Math.log(a)*m; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return Math.pow(a, Q)*logam; + } + }; + } + }; + + public static final Function INSTANCE = new Exp(); + + public Exp() { + super( + "exp", + "W(Q) = m * a^Q + b", + new String [] { "m", "a", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + return parameters[0]*Math.pow(parameters[1], x) + parameters[2]; + } + + @Override + public double [] gradient(double Q, double [] parameters) { + double m = parameters[0]; + double a = parameters[1]; + double b = parameters[2]; + return new double [] { + Math.pow(a, Q), + Math.pow(a, Q-1d)*m*Q, + 1d + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvExp.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,100 @@ +package de.intevation.flys.artifacts.math.fitting; + +import org.apache.commons.math.FunctionEvaluationException; + +import org.apache.commons.math.optimization.fitting.ParametricRealFunction; + +import de.intevation.flys.utils.DoubleUtil; + +public abstract class Function +implements ParametricRealFunction +{ + protected String name; + protected String description; + protected String [] parameterNames; + protected double [] initialGuess; + + public static abstract class Derivative { + + protected String description; + + public Derivative() { + } + + public Derivative(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + + public abstract de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters); + + } // interface Derivative + + public Function() { + } + + public Function( + String name, + String description, + String [] parameterNames + ) { + this(name, + description, + parameterNames, + DoubleUtil.fill(parameterNames.length, 1d)); + } + + public Function( + String name, + String description, + String [] parameterNames, + double [] initialGuess + ) { + this.name = name; + this.description = description; + this.parameterNames = parameterNames; + this.initialGuess = initialGuess; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public String [] getParameterNames() { + return parameterNames; + } + + public double [] getInitialGuess() { + return initialGuess; + } + + public de.intevation.flys.artifacts.math.Function instantiate( + final double [] parameters + ) { + return new de.intevation.flys.artifacts.math.Function() { + + @Override + public double value(double x) { + try { + return Function.this.value(x, parameters); + } + catch (FunctionEvaluationException fee) { + return Double.NaN; + } + } + }; + } + + public abstract Derivative getDerivative(); + + public abstract Function getInverse(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,44 @@ +package de.intevation.flys.artifacts.math.fitting; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +public final class FunctionFactory +{ + private static FunctionFactory instance; + + private Map<String, Function> functions; + + private FunctionFactory() { + functions = new LinkedHashMap<String, Function>(); + + registerFunction(Log.INSTANCE); + registerFunction(Linear.INSTANCE); + registerFunction(LogLinear.INSTANCE); + registerFunction(Exp.INSTANCE); + registerFunction(Quad.INSTANCE); + registerFunction(Pow.INSTANCE); + registerFunction(SQPow.INSTANCE); + } + + public static synchronized FunctionFactory getInstance() { + if (instance == null) { + instance = new FunctionFactory(); + } + return instance; + } + + public Function getFunction(String name) { + return functions.get(name); + } + + public void registerFunction(Function function) { + functions.put(function.getName(), function); + } + + public Collection<Function> getFunctions() { + return functions.values(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvExp.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,66 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvExp +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = 1/(log(a)*(Q-b))") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double a = parameters[1]; + final double b = parameters[2]; + final double loga = Math.log(a); + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return 1d/(loga*(Q-a)); + } + }; + } + }; + + public static final Function INSTANCE = new InvExp(); + + public InvExp() { + super( + "inv-exp", + "Q(W) = log((W-b)/m)/log(a)", + new String [] { "m", "a", "b" }); + } + + @Override + public double value(double W, double [] parameters) { + double m = parameters[0]; + double a = parameters[1]; + double b = parameters[2]; + return Math.log((W-b)/m)/Math.log(a); + } + + @Override + public double [] gradient(double Q, double [] parameters) { + double m = parameters[0]; + double a = parameters[1]; + double b = parameters[2]; + double loga = Math.log(a); + return new double [] { + -1d/(loga*m), + -Math.log((Q-b)/m)/(a*loga*loga), + -1d/(loga*(Q-b)) + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return Exp.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvLinear.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,57 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvLinear +extends Function +{ + public static Function INSTANCE = new InvLinear(); + + public static final Derivative DERIVATIVE = + new Derivative("Q'(W) = 1/m") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double _1m = 1d/parameters[0]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return _1m; + } + }; + } + }; + + public InvLinear() { + super("inv-linear", "W(Q) = (Q-b)/m", new String [] { "m", "b" }); + } + + @Override + public double value(double Q, double [] parameters) { + double m = parameters[0]; + double b = parameters[1]; + return (Q-b)/m; + } + + @Override + public double [] gradient(double Q, double [] parameters) { + double m = parameters[0]; + double b = parameters[1]; + return new double [] { + -(Q-b)/(m*m), + -1d/m + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return Linear.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvLog.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,55 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvLog +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("Q'(W) = exp(W/m)/m") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double _1m = 1d / parameters[0]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double W) { + return Math.exp(W*_1m)*_1m; + } + }; + } + }; + + public static final Function INSTANCE = new InvLog(); + + public InvLog() { + super("inv-log", "Q(W) = e^(W/m) - b", new String [] { "m", "b" }); + } + + @Override + public double value(double w, double [] parameters) { + double m = parameters[0]; + double b = parameters[1]; + return Math.exp(w/m) - b; + } + + @Override + public double [] gradient(double w, double [] parameters) { + double m = parameters[0]; + double b = parameters[1]; + double ewm = Math.exp(w/m); + return new double [] { -w*ewm/(m*m), -1 }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return Log.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvLogLinear +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("Q'(W) = e^(W/a)/(a*m)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double _1a = 1d/parameters[0]; + final double _1am = 1d/(parameters[0] * parameters[1]); + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double W) { + return Math.exp(W*_1a)*_1am; + } + }; + } + }; + public static final Function INSTANCE = new InvLogLinear(); + + public InvLogLinear() { + super( + "inv-log-linear", + "Q(W)=(e^(W/a)-b)/m", + new String [] { "a", "m", "b" }); + } + + @Override + public double value(double W, double [] parameters) { + double a = parameters[0]; + double m = parameters[1]; + double b = parameters[2]; + return (Math.exp(W/a) - b)/m; + } + + @Override + public double [] gradient(double W, double [] parameters) { + double a = parameters[0]; + double m = parameters[1]; + double b = parameters[2]; + double eWa = Math.exp(W/a); + return new double [] { + -(W*eWa)/(a*a*m) + -(eWa-b)/(m*m), + -1/m + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return LogLinear.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,72 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvPow +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("Q'(W) = ((W-d)/a)^(1/c)/(c*(W-d))") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + double a = parameters[0]; + final double c = parameters[1]; + final double d = parameters[2]; + final double _1a = 1d/a; + final double _1c = 1d/c; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double W) { + double Wd = W-d; + return Math.pow(Wd*_1a, _1c)/(c*Wd); + } + }; + } + }; + + public static final Function INSTANCE = new InvPow(); + + public InvPow() { + super( + "pow", + "Q(W) = ((W-d)/a)^(1/c)", + new String [] { "a", "c", "d" }); + } + + @Override + public double value(double W, double [] parameters) { + double a = parameters[0]; + double c = parameters[1]; + double d = parameters[2]; + return Math.pow((W-d)/a, 1d/c); + } + + @Override + public double [] gradient(double W, double [] parameters) { + double a = parameters[0]; + double c = parameters[1]; + double d = parameters[2]; + double _1c = 1d/c; + double Wdac = Math.pow((W-d)/a, 1d/c); + double Wd = W-d; + return new double [] { + -Wdac/(a*c), + (Wdac*Math.log(Wd/a))/(c*c), + -Wdac/(c*Wd) + }; + } + + @Override + public Derivative getDerivative() { + // TODO: Implement me! + return null; + } + + @Override + public Function getInverse() { + return Pow.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,69 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvQuad +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("Q'(W) = 1/sqrt(4*n*(W-b)+m^2)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + double n = parameters[0]; + double m = parameters[1]; + final double b = parameters[2]; + final double n4 = 4d*n; + final double mm = m*m; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double W) { + return 1d/Math.sqrt(n4*(W-b)+mm); + } + }; + } + }; + + public static final Function INSTANCE = new InvQuad(); + + public InvQuad() { + super( + "inv-quad", + "(sqrt(4*n*W-4*b*n+m^2)-m)/(2*n)", + new String [] { "n", "m", "b" }); + } + + @Override + public double value(double W, double [] parameters) { + double n = parameters[0]; + double m = parameters[1]; + double b = parameters[2]; + return (Math.sqrt(4d*n*(W - b) + m*m)-m)/(2d*n); + } + + @Override + public double [] gradient(double W, double [] parameters) { + double n = parameters[0]; + double m = parameters[1]; + double b = parameters[2]; + double Wb = W-b; + double sn4Wb = Math.sqrt(4d*n*Wb + m*m); + return new double [] { + Wb/(n*sn4Wb)-(sn4Wb-m)/(2d*n*n), + (m/sn4Wb-1d)/(2d*n), + -1d/sn4Wb + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return Quad.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class InvSQPow +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("Q'(S) = (S/a)^(1/b)/(b*S)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double _1a = 1d/parameters[0]; + final double b = parameters[1]; + final double _1b = 1d/b; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double S) { + return Math.pow(S*_1a, _1b)/(b*S); + } + }; + } + }; + public static final Function INSTANCE = new InvSQPow(); + + public InvSQPow() { + super( + "inv-sq-pow", + "Q(S) = Q=(S/a)^(1/b)", + new String [] { "a", "b" }); + } + + @Override + public double value(double S, double [] parameters) { + double a = parameters[0]; + double b = parameters[1]; + return Math.pow(S/a, 1d/b); + } + + @Override + public double [] gradient(double S, double [] parameters) { + double a = parameters[0]; + double b = parameters[1]; + double Sa = S/a; + double _1b = 1d/b; + double eSa1b = Math.pow(Sa, _1b); + return new double [] { + -eSa1b/(a*b), + -(eSa1b*Math.log(Sa))/(b*b) + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return SQPow.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,50 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class Linear +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = m") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double m = parameters[0]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return m; + } + }; + } + }; + + public static final Function INSTANCE = new Linear(); + + public Linear() { + super("linear", "W(Q) = m*Q + b", new String [] { "m", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + return x*parameters[0] + parameters[1]; + } + + @Override + public double [] gradient(double x, double [] parameters) { + return new double [] { x, 1d }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvLinear.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,57 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class Log +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = m/(Q+b)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double m = parameters[0]; + final double b = parameters[1]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return m/(Q+b); + } + }; + } + }; + + public static final Function INSTANCE = new Log(); + + public Log() { + super("log", "W(Q) = m*ln(Q + b)", new String [] { "m", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + return parameters[0]*Math.log(x + parameters[1]); + } + + @Override + public double [] gradient(double x, double [] parameters) { + double m = parameters[0]; + double b = parameters[1]; + double b_x = b + x; + return new double [] { + Math.log(b_x), + m/b_x + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvLog.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,65 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class LogLinear +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = a*m/(m*Q + b)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double a = parameters[0]; + final double m = parameters[1]; + final double b = parameters[2]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return a*m/(m*Q + b); + } + }; + } + }; + + public static final Function INSTANCE = new LogLinear(); + + public LogLinear() { + super( + "log-linear", + "W(Q) = a*ln(m*Q + b)", + new String [] { "a", "m", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + return parameters[0]*Math.log(parameters[1]*x + parameters[2]); + } + + @Override + public double [] gradient(double x, double [] parameters) { + double a = parameters[0]; + double m = parameters[1]; + double b = parameters[2]; + + double lin = m*x + b; + + return new double [] { + Math.log(lin), + a*x / lin, + a / lin + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvLogLinear.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class Pow +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = a*c*Q^(c-1)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double a = parameters[0]; + final double c = parameters[1]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return a*c*Math.pow(Q, c-1); + } + }; + } + }; + + public static final Function INSTANCE = new Pow(); + + public Pow() { + super( + "pow", + "W(Q) = a*Q^c + d", + new String [] { "a", "c", "d" }); + } + + @Override + public double value(double x, double [] parameters) { + return parameters[0]*Math.pow(x, parameters[1]) + parameters[2]; + } + + @Override + public double [] gradient(double x, double [] parameters) { + double a = parameters[0]; + double c = parameters[1]; + double x_c = Math.pow(x, c); + return new double [] { + x_c, + a*x_c*Math.log(x), + 1d + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvPow.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,55 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class Quad +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("W'(Q) = 2*n*Q+m") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double n2 = 2d*parameters[0]; + final double m = parameters[1]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return n2*Q+m; + } + }; + } + }; + + public static final Function INSTANCE = new Quad(); + + public Quad() { + super( + "quad", + "W(Q) = n*Q^2 + m*Q + b", + new String [] { "n", "m", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + // n*Q^2 + m*Q + b <=> Q*(n*Q + m) + b + return x*(parameters[0]*x + parameters[1]) + parameters[2]; + } + + @Override + public double [] gradient(double x, double [] parameters) { + return new double [] { x*x, x, 1d }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvQuad.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,60 @@ +package de.intevation.flys.artifacts.math.fitting; + +public class SQPow +extends Function +{ + public static final Derivative DERIVATIVE = + new Derivative("S'(Q) = a*b*Q^(b-1)") { + + @Override + public de.intevation.flys.artifacts.math.Function + instantiate(double [] parameters) + { + final double a = parameters[0]; + final double b = parameters[1]; + + return new de.intevation.flys.artifacts.math.Function() { + @Override + public double value(double Q) { + return a*b*Math.pow(Q, b-1); + } + }; + } + }; + + public static final Function INSTANCE = new SQPow(); + + public SQPow() { + super( + "sq-pow", + "S(Q) = a*Q^b", + new String [] { "a", "b" }); + } + + @Override + public double value(double x, double [] parameters) { + return parameters[0]*Math.pow(x, parameters[1]); + } + + @Override + public double [] gradient(double q, double [] parameters) { + double a = parameters[0]; + double b = parameters[1]; + double q_b = Math.pow(q, b); + return new double [] { + q_b, + a*q_b*Math.log(q), + }; + } + + @Override + public Derivative getDerivative() { + return DERIVATIVE; + } + + @Override + public Function getInverse() { + return InvSQPow.INSTANCE; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,95 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.AnnotationArtifact; + +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StickyAxisAnnotation; + +import de.intevation.flys.model.Annotation; +import de.intevation.flys.model.FastAnnotations; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * Facet to access Annotations (landmarks, POIs) of a river. + */ +public class AnnotationFacet +extends DefaultFacet +{ + /** Logger for this class. */ + private static final Logger logger = Logger.getLogger(AnnotationFacet.class); + + + /** + * Trivial Constructor. + */ + public AnnotationFacet() { + } + + + /** + * Trivial Constructor for a AnnotationFacet. + * + * @param index Database-Index to use. + * @param name Name (~type) of Facet. + * @param description Description of Facet. + */ + public AnnotationFacet(int index, String name, String description) { + super(index, name, description); + } + + + /** + * Get List of Annotations for river from Artifact. + * + * @param artifact (Annotation-)Artifact to query for list of Annotations. + * @param context Ignored. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + AnnotationArtifact annotationArtifact = (AnnotationArtifact) artifact; + + String riverName = FLYSUtils.getRivername((FLYSArtifact)artifact); + + FastAnnotations fas = LocationProvider.getAnnotations(riverName); + + List<StickyAxisAnnotation> xy = + new ArrayList<StickyAxisAnnotation>(fas.size()); + + for (Iterator<FastAnnotations.Annotation> iter = + fas.filter(FastAnnotations.IS_POINT); iter.hasNext();) { + FastAnnotations.Annotation fa = iter.next(); + + xy.add(new StickyAxisAnnotation( + fa.getPosition(), + (float)fa.getA(), + StickyAxisAnnotation.SimpleAxis.X_AXIS)); + } + + return new FLYSAnnotation(description, xy); + } + + + @Override + public Facet deepCopy() { + AnnotationFacet copy = new AnnotationFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,114 @@ +package de.intevation.flys.artifacts.model; + +import java.math.BigDecimal; + +import java.util.List; +import java.util.Iterator; +import java.util.Collections; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.Annotation; +import de.intevation.flys.model.Range; +import de.intevation.flys.model.River; + +import org.hibernate.Session; +import org.hibernate.Query; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class AnnotationsFactory { + + /** + * Get Annotations which do not have a "b" ("to")-value set. + * + * @param river name of the river of interest. + * + * @return List of Annotations for river which have only "a" ("from") + * value set. + */ + public static List<Annotation> getPointAnnotations(String river) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from Annotation as an " + + "where an.range.b = null and an.range.river.name=:name " + + "order by range.a"); + query.setParameter("name", river); + return query.list(); + } + + + public static List<Annotation> getAnnotations(River river) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from Annotation as an where an.range.river = :river" + + " order by an.range.a"); + query.setParameter("river", river); + return query.list(); + } + + + public static Annotation getAnnotation(String river, double km) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from Annotation as a " + + "where a.range.river.name = :river AND a.range.a = :km"); + + query.setParameter("river", river); + query.setParameter("km", BigDecimal.valueOf(km)); + + List<Annotation> result = query.list(); + + return result != null && result.size() > 0 ? result.get(0) : null; + } + + + /** + * Get minimal "a" ("from") and maximal "b" ("to") value of annotations' + * ranges of a river. + * + * @param river name of the river of interest. + * + * @return Array containing minimal "a" and max "b" value of any + * annotation stored for the given river. + */ + public static double[] getAnnotationsBreadth(String river) { + Session session = SessionHolder.HOLDER.get(); + + Query minAQuery = session.createQuery( + "select min(a), max(b) from Range where river.name=:name"); + minAQuery.setParameter("name", river); + + double[] minAmaxB = {0.0f, 0.0f}; + Object[] row = (Object[]) minAQuery.list().iterator().next(); + minAmaxB[0] = ((BigDecimal) row[0]).doubleValue(); + minAmaxB[1] = ((BigDecimal) row[1]).doubleValue(); + return minAmaxB; + } + + + public static Iterator<Annotation> getAnnotationsIterator( + String riverName + ) { + Session session = SessionHolder.HOLDER.get(); + + Query riverQuery = session.createQuery( + "from River where name = :name"); + riverQuery.setParameter("name", riverName); + List<River> rivers = riverQuery.list(); + if (rivers.isEmpty()) { + return Collections.<Annotation>emptyList().iterator(); + } + + Query query = session.createQuery( + "from Annotation as an" + + " where an.range.river = :river order by an.range.a"); + query.setParameter("river", rivers.get(0)); + + return (Iterator<Annotation>)query.iterate(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,145 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.DataProvider; + +import de.intevation.flys.artifacts.AreaArtifact; + + +/** + * Trival Facet for areas. + * Note that this Facet comes in two "types" (names): + * <ul> + * <li>CROSS_SECTION_AREA (cross_section.area) and</li> + * <li>LONGITUDINAL_SECTION_AREA (longitudinal.area</li> + * </ul> + * This is to support different diagram types without being painted in both + * at the same time. The name has to be given when constructing. + */ +public class AreaFacet +extends DefaultFacet +{ + private static Logger logger = Logger.getLogger(AreaFacet.class); + + /** + * Constructor, set (maybe localized) description and name. + * @param idx Index given when querying artifact for data. + * @param name important to discern areas in different diagram types. + */ + public AreaFacet(int idx, String name, String description) { + super(idx, name, description); + } + + + /** + * Gets Cross Section (profile). + * @param art artifact to get data from. + * @param context ignored + */ + public Object getData(Artifact art, CallContext context) { + logger.debug("Get data for area."); + + // Get information from artifact about which + // info to grab from blackboard. + // + // All compatible facets should provide their data + // under the key (Artifact-UUID + Facet-Index). + AreaArtifact artifact = (AreaArtifact) art; + Object lowerData = null; + Object upperData = null; + String stemFacetName = null; + + List<DataProvider> providers = context. + getDataProvider(artifact.getLowerDPKey()); + if (providers.size() < 1) { + logger.warn("No 'lower' provider given for area [" + + artifact.getLowerDPKey() + "]"); + } + else { + lowerData = providers.get(0).provideData( + artifact.getLowerDPKey(), null, context); + logger.debug("'Lower' data provider key for area [" + + artifact.getLowerDPKey() + "]"); + stemFacetName = artifact.getLowerDPKey().split(":")[1]; + } + + providers = context.getDataProvider(artifact.getUpperDPKey()); + if (providers.size() < 1) { + logger.warn("No 'upper' provider given for area [" + + artifact.getUpperDPKey() + "]"); + } + else { + upperData = providers.get(0).provideData( + artifact.getUpperDPKey(), null, context); + logger.debug("'Upper' data provider key for area [" + + artifact.getUpperDPKey() + "]"); + if (stemFacetName == null) { + stemFacetName = artifact.getUpperDPKey().split(":")[1]; + } + } + + if (upperData == null && lowerData == null) { + logger.warn("Not given 'upper' and 'lower' for area"); + } + + return new Data(stemFacetName, lowerData, upperData, + Boolean.valueOf(artifact.getPaintBetween())); + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + AreaFacet copy = new AreaFacet(this.index, this.name, this.description); + copy.set(this); + return copy; + } + + /** Result data bundle. */ + public class Data { + protected String rootFacetName; + protected Object upperData; + protected Object lowerData; + protected boolean doPaintBetween; + + /** Create a new result data bundle. */ + public Data(String rootName, Object low, Object up, boolean between) { + this.rootFacetName = rootName; + this.lowerData = low; + this.upperData = up; + this.doPaintBetween = between; + } + + /** Get name of a facet that is involved in area generation + * to induce type (e.g. longitudinal_section.w -> "W over km"). */ + public String getRootFacetName() { + return this.rootFacetName; + } + + /** Get data for 'upper' curve of area. */ + public Object getUpperData() { + return this.upperData; + } + + /** Get data for 'lower' curve of area. */ + public Object getLowerData() { + return this.lowerData; + } + + /** Whether to fill whole area between (in contrast to 'under' + * or 'over'). */ + public boolean doPaintBetween() { + return this.doPaintBetween; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,78 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.DefaultFacet; + + +/** + * Facet that writes artifact-uui and facet index on the blackboard, + * delivers data if asked so. + */ +public class BlackboardDataFacet extends DefaultFacet { + + public BlackboardDataFacet() {} + + /** Do not instantiate a BlackboardDataFacet, subclass it instead. */ + public BlackboardDataFacet(int idx, String name, String description) { + super(idx, name, description); + } + + + /** Do not instantiate a BlackboardDataFacet, subclass it instead. */ + public BlackboardDataFacet(String name, String description) { + super(0, name, description); + } + + + /** Define key to which to respond when asked for 'blackboard' + * (DataProvider)- data. */ + public String areaDataKey(Artifact art) { + return art.identifier() + ":" + getName() + ":" + getIndex(); + } + + + /** Hey, We can ArtifactUUID+:+FacetName+:+FacetIndex (i.e. getData)! */ + @Override + public List getStaticDataProviderKeys(Artifact art) { + List list = new ArrayList(); + list.add(areaDataKey(art)); + return list; + } + + + /** + * Can provide whatever getData returns. + * @param key will respond on uuid+index + * @param param ignored + * @param context ignored + * @return whatever getData delivers. + */ + @Override + public Object provideBlackboardData(Artifact artifact, + Object key, + Object param, + CallContext context + ) { + if (key.equals(areaDataKey(artifact))) { + return getData(artifact, context); + } + else { + return null; + } + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + BlackboardDataFacet copy = new BlackboardDataFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,155 @@ +package de.intevation.flys.artifacts.model; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import java.io.Serializable; + +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.Formatter; + +public class Calculation +implements Serializable +{ + public static class Problem + implements Serializable + { + protected Double km; + protected String msg; + protected Object [] args; + + public Problem() { + } + + public Problem(String msg) { + this.msg = msg; + } + + public Problem(String msg, Object [] args) { + this.msg = msg; + this.args = args; + } + + public Problem(double km, String msg) { + this.km = km; + this.msg = msg; + } + + public Problem(double km, String msg, Object [] args) { + this.km = km; + this.msg = msg; + this.args = args; + } + + public Element toXML(Document document, CallMeta meta) { + Element problem = document.createElement("problem"); + if (km != null) { + problem.setAttribute( + "km", + Formatter.getCalculationKm(meta).format(km)); + } + String text = args != null + ? Resources.getMsg(meta, msg, msg, args) + : Resources.getMsg(meta, msg, msg); + problem.setTextContent(text); + return problem; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Problem)) { + return false; + } + Problem o = (Problem)other; + return !(!msg.equals(o.msg) + || (km == null && o.km != null) + || (km != null && o.km == null) + || (km != null && !km.equals(o.km)) + || !Arrays.equals(args, o.args)); + } + } // class Problem + + protected List<Problem> problems; + + public Calculation() { + } + + public Calculation(String msg) { + addProblem(msg); + } + + protected List<Problem> checkProblems() { + if (problems == null) { + problems = new ArrayList<Problem>(); + } + return problems; + } + + public void addProblems(Calculation other) { + List<Problem> otherProblems = other.problems; + if (otherProblems != null) { + List<Problem> problems = checkProblems(); + for (Problem problem: otherProblems) { + if (!problems.contains(problem)) { + problems.add(problem); + } + } + } + } + + public void addProblem(Problem problem) { + List<Problem> problems = checkProblems(); + if (!problems.contains(problem)) { + problems.add(problem); + } + } + + public void addProblem(String msg) { + addProblem(new Problem(msg)); + } + + public void addProblem(String msg, Object ... args) { + addProblem(new Problem(msg, args)); + } + + public void addProblem(double km, String msg) { + addProblem(new Problem(km, msg)); + } + + public void addProblem(double km, String msg, Object ... args) { + addProblem(new Problem(km, msg, args)); + } + + public boolean hasProblems() { + return problems != null && !problems.isEmpty(); + } + + public int numProblems() { + return problems != null ? problems.size() : 0; + } + + public List<Problem> getProblems() { + return problems; + } + + public void toXML(Document document, CallMeta meta) { + + Element root = document.createElement("problems"); + + if (hasProblems()) { + for (Problem problem: problems) { + root.appendChild(problem.toXML(document, meta)); + } + } + + document.appendChild(root); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation1.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +public class Calculation1 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation1.class); + + protected double [] kms; + protected double [] qs; + protected double [] ws; + protected double refKm; + + public Calculation1() { + } + + public Calculation1( + double [] kms, + double [] qs, + double [] ws, + double refKm + ) { + this.kms = kms; + this.qs = qs; + this.ws = ws; + this.refKm = refKm; + } + + public CalculationResult calculate(WstValueTable wst) { + + ArrayList<WQKms> results = new ArrayList<WQKms>(); + + String prefix; + double [] origData; + + if (ws != null) { prefix = "W="; origData = ws; } + else { prefix = "Q="; origData = qs; } + + int oldNumProblems = numProblems(); + + for (int i = 0; i < qs.length; i++) { + + double [] oqs = new double[kms.length]; + double [] ows = new double[kms.length]; + + boolean success = + wst.interpolate(qs[i], refKm, kms, ows, oqs, this) != null; + + int newNumProblems = numProblems(); + + if (success) { + WQKms result = new WQKms(kms, oqs, ows, prefix + origData[i]); + if (oldNumProblems != newNumProblems) { + logger.debug( + qs[i] + " caused " + (newNumProblems-oldNumProblems) + + " new problem(s)."); + result.removeNaNs(); + } + results.add(result); + } + + oldNumProblems = newNumProblems; + } + + return new CalculationResult( + results.toArray(new WQKms[results.size()]), + this); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation2.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,50 @@ +package de.intevation.flys.artifacts.model; + +import java.util.Arrays; + +import org.apache.log4j.Logger; + + +/** ComputedDischargeCurve. */ +public class Calculation2 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation2.class); + + protected double km; + + public Calculation2() { + } + + public Calculation2(double km) { + this.km = km; + } + + public CalculationResult calculate(WstValueTable wst) { + + logger.debug("Calculation2.calculate"); + + double [][] wqs = wst.interpolateWQ(km, this); + + if (wqs == null || wqs[0].length == 0) { + addProblem("cannot.compute.discharge.curve"); + return new CalculationResult(new WQKms[0], this); + } + + double [] ws = wqs[0]; + double [] qs = wqs[1]; + double [] kms = new double[ws.length]; + + Arrays.fill(kms, km); + + WQKms wqkms = new WQKms(kms, qs, ws, String.valueOf(km)); + + if (hasProblems()) { + logger.debug("found " + numProblems() + " problems."); + wqkms.removeNaNs(); + } + + return new CalculationResult(new WQKms[] { wqkms }, this); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation3.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,49 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +public class Calculation3 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation3.class); + + protected double km; + protected int [] days; + protected double [] qs; + + public Calculation3() { + } + + public Calculation3(double km, int [] days, double [] qs) { + this.km = km; + this.days = days; + this.qs = qs; + } + + public CalculationResult calculate(WstValueTable wst) { + + double [] ws = wst.interpolateW(km, qs, new double[qs.length], this); + + if (days == null || days.length == 0) { + addProblem(km, "cannot.find.ds"); + } + + if (logger.isDebugEnabled()) { + logger.debug("Calculate duration curve data:"); + logger.debug(" km : " + km); + logger.debug(" num Days : " + (days != null ? days.length : 0)); + logger.debug(" num Qs : " + (qs != null ? qs.length : 0)); + logger.debug(" result Ws: " + (ws != null ? ws.length : 0)); + } + + WQDay wqday = new WQDay(days, ws, qs); + + if (hasProblems()) { + logger.debug("calculation caused "+numProblems()+" problem(s)."); + wqday.removeNaNs(); + } + + return new CalculationResult(wqday, this); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,251 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.BackJumpCorrector; +import de.intevation.flys.artifacts.math.Function; +import de.intevation.flys.artifacts.math.Identity; +import de.intevation.flys.artifacts.math.Linear; + +import de.intevation.flys.artifacts.model.WstValueTable.QPosition; + +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.DoubleUtil; + +import java.util.Arrays; +import java.util.List; + +import org.apache.log4j.Logger; + +public class Calculation4 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation4.class); + + public static final double MINIMAL_STEP_WIDTH = 1e-5; + + protected List<Segment> segments; + + protected boolean isQ; + + public Calculation4() { + } + + public Calculation4(List<Segment> segments, River river, boolean isQ) { + + this.segments = segments; + this.isQ = isQ; + + Segment.setReferencePointConvertQ(segments, river, isQ, this); + } + + public CalculationResult calculate( + WstValueTable table, + double from, double to, double step + ) { + boolean debug = logger.isDebugEnabled(); + + if (debug) { + logger.debug( + "calculate from " + from + " to " + to + " step " + step); + logger.debug("# segments: " + segments.size()); + for (Segment segment: segments) { + logger.debug(" " + segment); + } + } + + if (segments.isEmpty()) { + logger.debug("no segments found"); + addProblem("no.segments.found"); + return new CalculationResult(new WQKms[0], this); + } + + int numResults = segments.get(0).values.length; + + if (numResults < 1) { + logger.debug("no values given"); + addProblem("no.values.given"); + return new CalculationResult(new WQKms[0], this); + } + + + WQKms [] results = new WQKms[numResults]; + for (int i = 0; i < results.length; ++i) { + results[i] = new WQKms(); + } + + if (Math.abs(step) < MINIMAL_STEP_WIDTH) { + step = MINIMAL_STEP_WIDTH; + } + + if (from > to) { + step = -step; + } + + QPosition [] qPositions = new QPosition[numResults]; + + Function [] functions = new Function[numResults]; + + double [] out = new double[2]; + + Segment sentinel = new Segment(Double.MAX_VALUE); + Segment s1 = sentinel, s2 = sentinel; + + for (double pos = from; + from < to ? pos <= to : pos >= to; + pos = DoubleUtil.round(pos + step) + ) { + if (pos < s1.referencePoint || pos > s2.referencePoint) { + if (debug) { + logger.debug("need to find new interval for " + pos); + } + // find new interval + if (pos <= segments.get(0).referencePoint) { + // before first segment -> "gleichwertig" + if (debug) { + logger.debug("before first segment -> gleichwertig"); + } + Segment first = segments.get(0); + double [] values = first.values; + double refPos = first.referencePoint; + for (int i = 0; i < qPositions.length; ++i) { + qPositions[i] = table.getQPosition( + refPos, values[i]); + } + sentinel.setReferencePoint(-Double.MAX_VALUE); + s1 = sentinel; + s2 = segments.get(0); + Arrays.fill(functions, Identity.IDENTITY); + } + else if (pos >= segments.get(segments.size()-1).referencePoint) { + // after last segment -> "gleichwertig" + if (debug) { + logger.debug("after last segment -> gleichwertig"); + } + Segment last = segments.get(segments.size()-1); + double [] values = last.values; + double refPos = last.referencePoint; + for (int i = 0; i < qPositions.length; ++i) { + qPositions[i] = table.getQPosition( + refPos, values[i]); + } + sentinel.setReferencePoint(Double.MAX_VALUE); + s1 = last; + s2 = sentinel; + Arrays.fill(functions, Identity.IDENTITY); + } + else { // "ungleichwertig" + // find matching interval + if (debug) { + logger.debug("in segments -> ungleichwertig"); + } + s1 = s2 = null; + for (int i = 1, N = segments.size(); i < N; ++i) { + Segment si1 = segments.get(i-1); + Segment si = segments.get(i); + if (debug) { + logger.debug("check " + pos + " in " + + si1.referencePoint + " - " + si.referencePoint); + } + if (pos >= si1.referencePoint + && pos <= si. referencePoint) { + s1 = si1; + s2 = si; + break; + } + } + + if (s1 == null) { + throw new IllegalStateException("no interval found"); + } + + Segment anchor, free; + + if (from > to) { anchor = s1; free = s2; } + else { anchor = s2; free = s1; } + + // build transforms based on "gleichwertiger" phase + for (int i = 0; i < qPositions.length; ++i) { + QPosition qi = table.getQPosition( + anchor.referencePoint, + anchor.values[i]); + + if ((qPositions[i] = qi) == null) { + addProblem(pos, "cannot.find.q", anchor.values[i]); + functions[i] = Identity.IDENTITY; + } + else { + double qA = table.getQ(qi, anchor.referencePoint); + double qF = table.getQ(qi, free .referencePoint); + + functions[i] = Double.isNaN(qA) || Double.isNaN(qF) + ? Identity.IDENTITY + : new Linear( + qA, qF, + anchor.values[i], free.values[i]); + + if (debug) { + logger.debug( + anchor.referencePoint + ": " + + qA + " -> " + functions[i].value(qA) + + " / " + free.referencePoint + ": " + + qF + " -> " + functions[i].value(qF)); + } + } + } // build transforms + } // "ungleichwertiges" interval + } // find matching interval + + for (int i = 0; i < qPositions.length; ++i) { + QPosition qPosition = qPositions[i]; + + if (qPosition == null) { + continue; + } + + if (table.interpolate(pos, out, qPosition, functions[i])) { + results[i].add(out[0], out[1], pos); + } + else { + addProblem(pos, "cannot.interpolate.w.q"); + } + } + } + + // Backjump correction + for (int i = 0; i < results.length; ++i) { + BackJumpCorrector bjc = new BackJumpCorrector(); + + double [] ws = results[i].getWs(); + double [] kms = results[i].getKms(); + + if (bjc.doCorrection(kms, ws, this)) { + results[i] = new WQCKms(results[i], bjc.getCorrected()); + } + } + + // name the curves + for (int i = 0; i < results.length; ++i) { + results[i].setName(createName(i)); + } + + return new CalculationResult(results, this); + } + + protected String createName(int index) { + // TODO: i18n + StringBuilder sb = new StringBuilder(isQ ? "Q" : "W"); + sb.append(" benutzerdefiniert ("); + for (int i = 0, N = segments.size(); i < N; ++i) { + if (i > 0) { + sb.append("; "); + } + Segment segment = segments.get(i); + sb.append((segment.backup != null + ? segment.backup + : segment.values)[index]); + } + sb.append(')'); + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation5.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,77 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.utils.Formatter; + +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.Map; + +import org.apache.log4j.Logger; + +public class Calculation5 +extends Calculation +{ + private static Logger log = Logger.getLogger(Calculation5.class); + + protected double startKm; + protected double [] endKms; + + public Calculation5() { + } + + public Calculation5(double startKm, double [] endKms) { + this.startKm = startKm; + this.endKms = endKms; + } + + public CalculationResult calculate( + WstValueTable wst, + Map<Double, Double> kms2gaugeDatums, + CallContext context + ) { + ArrayList<WWQQ> results = new ArrayList<WWQQ>(); + + int numProblems = numProblems(); + + CallMeta meta = context.getMeta(); + + for (double endKm: endKms) { + + double [][] wws = wst.relateWs(startKm, endKm, this); + int newNumProblems = numProblems(); + + if (wws.length == 4) { + WWQQ wwqq = new WWQQ( + generateName(meta, startKm, endKm), + startKm, kms2gaugeDatums.get(startKm), wws[0], wws[1], + endKm, kms2gaugeDatums.get(endKm), wws[2], wws[3]); + + if (newNumProblems > numProblems) { + wwqq.removeNaNs(); + } + + results.add(wwqq); + } + numProblems = newNumProblems; + } + + return new CalculationResult( + results.toArray(new WWQQ[results.size()]), + this); + } + + protected static String generateName( + CallMeta meta, + double startKm, + double endKm + ) { + NumberFormat nf = Formatter.getCalculationKm(meta); + return "W(km " + nf.format(startKm) + + ") ~ W(km " + nf.format(endKm) + ")"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,315 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.TimeInterval; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class Calculation6 extends Calculation { + + private static final Logger logger = Logger.getLogger(Calculation6.class); + + private int mode; + private long[] timerange; + private double[] values; + + + public static final int MODE_W = 0; + public static final int MODE_Q = 1; + + public static final double SCALE = 100d; + + + public Calculation6(int mode, long[] timerange, double[] values) { + this.mode = mode; + this.timerange = timerange; + this.values = values; + } + + + public CalculationResult calculate(Gauge gauge) { + if (!checkParameters() || gauge == null) { + logger.warn("Parameters not valid for calculation."); + + return null; + } + + if (logger.isDebugEnabled()) { + debug(); + } + + DischargeTable refTable = fetchReferenceTable(gauge); + List<DischargeTable> dts = fetchDischargeTables(gauge); + + int numTables = dts.size(); + + logger.debug("Take " + numTables + " into account."); + + if (numTables == 0) { + addProblem("cannot.find.hist.q.tables"); + } + + WQTimerange[] wqt = prepareCalculationData(refTable, dts); + + logger.debug("Number of calculation results: " + wqt.length); + + return new CalculationResult(wqt, this); + } + + + protected boolean checkParameters() { + if (!(mode == MODE_W || mode == MODE_Q)) { + logger.warn("Invalid mode '" + mode + "' for calculation."); + return false; + } + + if (timerange == null || timerange.length < 2) { + logger.warn("Invalid timerange for calculation."); + return false; + } + + if (values == null || values.length == 0) { + logger.warn("No values for W or Q specified."); + return false; + } + + return true; + } + + + protected DischargeTable fetchReferenceTable(Gauge gauge) { + return gauge.fetchMasterDischargeTable(); + } + + + protected List<DischargeTable> fetchDischargeTables(Gauge gauge) { + List<DischargeTable> relevant = new ArrayList<DischargeTable>(); + List<DischargeTable> all = gauge.getDischargeTables(); + + for (DischargeTable dt: all) { + if (isDischargeTableRelevant(dt)) { + relevant.add(dt); + } + } + + return relevant; + } + + + protected boolean isDischargeTableRelevant(DischargeTable dt) { + TimeInterval ti = dt.getTimeInterval(); + + if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE || ti == null) { + return false; + } + + Date start = ti.getStartTime(); + long startTime = start.getTime(); + + if (startTime >= timerange[0] && startTime <= timerange[1]) { + return true; + } + + Date stop = ti.getStopTime(); + long stopTime = stop != null ? stop.getTime() : -1l; + + if (stopTime >= timerange[0] && stopTime <= timerange[1]) { + return true; + } + + logger.debug("DischargeTable not in range: " + start + " -> " + stop); + + return false; + } + + + protected WQTimerange[] prepareCalculationData( + DischargeTable refTable, + List<DischargeTable> dts + ) { + if (refTable == null) { + addProblem("cannot.find.hist.q.reftable"); + return prepareSimpleData(dts); + } + else { + return prepareData(refTable, dts); + } + } + + + protected WQTimerange[] prepareSimpleData(List<DischargeTable> dts) { + List<WQTimerange> wqts = + new ArrayList<WQTimerange>(values.length); + + for (double value: values) { + logger.debug("Prepare data for value: " + value); + + String name = mode == MODE_W ? "W=" + value : "Q=" + value; + WQTimerange wqt = null; + + for (DischargeTable dt: dts) { + Date[] ti = prepareTimeInterval(dt); + Timerange t = new Timerange(ti[0], ti[1]); + double w; + double q; + + if (mode == MODE_W) { + w = value; + q = findValueForW(dt, w); + + if (Double.isNaN(q)) { + logger.warn("Cannot find Q for W: " + w); + addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]); + continue; + } + } + else { + q = value; + w = findValueForQ(dt, q); + } + + logger.debug("Q=" + q + " | W=" + w); + + if (wqt == null) { + wqt = new WQTimerange(name); + } + + wqt.add(w, q, t); + } + + if (wqt != null) { + wqts.add(wqt); + } + } + + return wqts.toArray(new WQTimerange[wqts.size()]); + } + + + protected HistoricalWQTimerange[] prepareData( + DischargeTable refTable, + List<DischargeTable> dts + ) { + List<HistoricalWQTimerange> wqts = + new ArrayList<HistoricalWQTimerange>(values.length); + + for (double value: values) { + logger.debug("Prepare data plus diff for value: " + value); + + String name = mode == MODE_W ? "W=" + value : "Q=" + value; + HistoricalWQTimerange wqt = null; + + double ref; + double diff; + + if (refTable != null && mode == MODE_W) { + ref = findValueForW(refTable, value); + } + else if (refTable != null) { + ref = findValueForQ(refTable, value); + } + else { + ref = Double.NaN; + } + + for (DischargeTable dt: dts) { + Date[] ti = prepareTimeInterval(dt); + + Timerange t = new Timerange(ti[0] ,ti[1]); + double w; + double q; + + if (mode == MODE_W) { + w = value; + q = findValueForW(dt, w); + + if (Double.isNaN(q)) { + logger.warn("Cannot find Q for W: " + w); + addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]); + continue; + } + + diff = ref-q; + } + else { + q = value; + w = findValueForQ(dt, q); + diff = ref-w; + } + + logger.debug("Q=" + q + " | W=" + w + " | Ref = " + ref); + + if (wqt == null) { + wqt = new HistoricalWQTimerange(name); + } + + wqt.add(w, q, diff, t); + } + + if (wqt != null) { + wqts.add(wqt); + } + } + + return (HistoricalWQTimerange[]) + wqts.toArray(new HistoricalWQTimerange[wqts.size()]); + } + + + protected Date[] prepareTimeInterval(DischargeTable dt) { + TimeInterval ti = dt.getTimeInterval(); + + Date start = ti.getStartTime(); + Date end = ti.getStopTime(); + + if (end == null) { + logger.warn("TimeInterval has no stop time set!"); + + end = new Date(); + } + + return new Date[] { start, end }; + } + + + protected double findValueForW(DischargeTable dt, double w) { + double[][] vs = DischargeTables.loadDischargeTableValues(dt, SCALE); + double [] qs = DischargeTables.getQsForW(vs, w); + return qs.length == 0 ? Double.NaN : qs[0]; + } + + + protected double findValueForQ(DischargeTable dt, double q) { + double[][] vs = DischargeTables.loadDischargeTableValues(dt, SCALE); + logger.warn("TODO: IMPLEMENT ME!"); + + return 10; + } + + + /** + * Writes the parameters used for this calculation to logger. + */ + public void debug() { + StringBuilder sb = new StringBuilder(); + for (double value: values) { + sb.append(String.valueOf(value) + " "); + } + + logger.debug("========== Calculation6 =========="); + logger.debug(" Mode: " + mode); + logger.debug(" Timerange: " + timerange[0] + " - " + timerange[1]); + logger.debug(" Input values: " + sb.toString()); + logger.debug("=================================="); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationMessage.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,46 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Message; + + +public class CalculationMessage implements Message { + + protected String message; + protected int steps; + protected int currentStep; + + + public CalculationMessage() { + } + + + public CalculationMessage(int steps, int currentStep, String message) { + this.steps = steps; + this.currentStep = currentStep; + this.message = message; + } + + + public int getSteps() { + return steps; + } + + + public int getCurrentStep() { + return currentStep; + } + + + public String getMessage() { + return message; + } + + + @Override + public String getText() { + return + String.valueOf(currentStep) + "/" + String.valueOf(steps) + + " - " + getMessage(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,45 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +/** + * Wraps result(s) of a Calculation and eventual error reports. + */ +public class CalculationResult +implements Serializable +{ + protected Object data; + protected Calculation report; + + public CalculationResult() { + } + + public CalculationResult(Calculation report) { + this(null, report); + } + + /** + * @param report report (e.g. error messages). + */ + public CalculationResult(Object data, Calculation report) { + this.data = data; + this.report = report; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public Calculation getReport() { + return report; + } + + public void setReport(Calculation report) { + this.report = report; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,122 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.CrossSectionArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Trival Facet for Cross Sections (profiles). + */ +public class CrossSectionFacet +extends BlackboardDataFacet +implements FacetTypes { + + public static String BLACKBOARD_CS_MASTER_DATA + = "crosssection.masterprofile.data"; + + public static String BLACKBOARD_CS_PREV_KM + = "crosssection.masterprofile.km.prev"; + + public static String BLACKBOARD_CS_NEXT_KM + = "crosssection.masterprofile.km.next"; + + + private static Logger logger = Logger.getLogger(CrossSectionFacet.class); + + protected ComputeType type; + + + /** Trivial constructor, set (maybe localized) description. */ + public CrossSectionFacet(int idx, String description) { + super(idx, CROSS_SECTION, description); + type = ComputeType.ADVANCE; + } + + + /** Tell world we know about crosssection masters data and its index. */ + public List getStaticDataProviderKeys(Artifact art) { + CrossSectionArtifact artifact = (CrossSectionArtifact) art; + List keys = new ArrayList(); + if (artifact.isMaster()) { + keys.add(BLACKBOARD_CS_MASTER_DATA); + keys.add(BLACKBOARD_CS_PREV_KM); + keys.add(BLACKBOARD_CS_NEXT_KM); + } + keys.add(artifact.identifier() + getIndex()); + keys.addAll(super.getStaticDataProviderKeys(art)); + return keys; + } + + + /** + * Can provide the master cross section lines or its index. + * @param artifact crosssection-artifact + * @param key will respond on BLACKBOARD_CS_MASTER_DATA + * @param param ignored + * @param context ignored + * @return data from artifact (cross section master track). + */ + public Object provideBlackboardData(Artifact artifact, + Object key, + Object param, + CallContext context + ) { + CrossSectionArtifact crossSection = (CrossSectionArtifact) artifact; + + if (key.equals(BLACKBOARD_CS_MASTER_DATA)) { + return crossSection.searchCrossSectionLine(); + } + else if (key.equals(artifact.identifier() + getIndex())) { + return getData(artifact, context); + } + else if (key.equals(BLACKBOARD_CS_NEXT_KM)) { + return crossSection.getNextKm(); + } + else if (key.equals(BLACKBOARD_CS_PREV_KM)) { + return crossSection.getPrevKm(); + } + else { + Object obj = super.provideBlackboardData(artifact, key, param, + context); + if (obj == null) { + logger.warn("Cannot provide data for key: " + key); + } + return obj; + } + } + + + /** + * Gets Cross Section (profile). + * @param art artifact to get data from. + * @param context ignored + */ + public Object getData(Artifact art, CallContext context) { + logger.debug("Get data for cross section"); + + CrossSectionArtifact artifact = (CrossSectionArtifact)art; + + return artifact.getCrossSectionData(); + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + CrossSectionFacet copy = new CrossSectionFacet(this.index, this.description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,112 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.CrossSection; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import org.hibernate.Session; +import org.hibernate.Query; + + +/** + * Get Cross Sections. + */ +public class CrossSectionFactory { + + protected final static String CACHE_NAME = "cross_sections"; + + // TODO use caching consistently, streamline acces. + /** + * Get CrossSections for an instantiated River. + * + * @param river river object. + * + * @return List of Cross Sections of river. + */ + public static List<CrossSection> getCrossSections(River river) { + return getCrossSections(river.getName()); + } + + + /** + * Get Cross Sections for a river by name. + * + * @param riverName name of the river of interest. + * + * @return List of Cross Sections of river. + */ + public static List<CrossSection> getCrossSections(String riverName) { + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from CrossSection where river.name = :rivername"); + query.setParameter("rivername", riverName); + return query.list(); + } + + + /** + * True if the given section is the "newest" for that river. + * @param section Given section + * @return true if the section has the most advanced end of its validity interval + * or the most advanced start of its validity interval. + */ + public static boolean isNewest(CrossSection section) { + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from CrossSection where river.id = :riverid " + + " order by timeInterval.stopTime desc, timeInterval.startTime desc"); + query.setParameter("riverid", section.getRiver().getId()); + + List result = query.list(); + + if (result == null || result.isEmpty()) { + return true; + } + else { + CrossSection cs = (CrossSection) result.get(0); + return section.getId().equals(cs.getId()); + } + } + + + /** + * Get a specific CrossSection from db. + * @param id The dbid of the cross-section to load. + */ + public static CrossSection getCrossSection(int id) { + Cache cache = CacheFactory.getCache(CACHE_NAME); + if (cache != null) { + Element element = cache.get(Integer.valueOf(id)); + if (element != null) { + return (CrossSection) element.getValue(); + } + } + + CrossSection section = getCrossSectionUncached(id); + if (cache != null) { + Element element = new Element(Integer.valueOf(id), section); + cache.put(element); + } + + return section; + } + + + /** Get specific CrossSection from database. */ + protected static CrossSection getCrossSectionUncached(int id) { + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from CrossSection where id=:id"); + query.setParameter("id", id); + List<CrossSection> list = query.list(); + return list.isEmpty() ? null : list.get(0); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,96 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import java.util.List; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.WaterLineArtifact; + +import de.intevation.flys.model.FastCrossSectionLine; + +import de.intevation.flys.artifacts.geom.Lines; + + +/** + * Facet for Waterlines in Cross Sections. + */ +public class CrossSectionWaterLineFacet +extends BlackboardDataFacet +implements FacetTypes { + + /** Private logger to use. */ + private static Logger logger = + Logger.getLogger(CrossSectionWaterLineFacet.class); + + + /** Trivial constructor, set (maybe localized) description. */ + public CrossSectionWaterLineFacet(int idx, String description) { + super(idx, CROSS_SECTION_WATER_LINE, description); + } + + + /** + * Trivial constructor, set (maybe localized) description. + * @param idx Index of this facet. + * @param name 'type' of this facet. + * @param description (maybe) localized user-visible description. + */ + public CrossSectionWaterLineFacet(int idx, String name, String description) { + super(idx, name, description); + } + + + /** + * Gets waterline (crossed with cross section) of waterlevel. + */ + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for cross section water line"); + + List<DataProvider> providers = context. + getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA); + if (providers.size() < 1) { + logger.warn("Could not find Cross-Section data provider."); + return new Lines.LineData(new double[][] {}, 0d, 0d); + } + + Object crossSection = providers.get(0) + .provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, + null, context); + Object nextKm = providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_NEXT_KM, null, context); + Object prevKm = providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_PREV_KM, null, context); + if (prevKm == null) + prevKm = new Double(-1d); + if (nextKm == null) + nextKm = new Double(-1d); + + WaterLineArtifact lineArtifact = (WaterLineArtifact) artifact; + + if (crossSection != null) { + return lineArtifact.getWaterLines(this.getIndex(), + (FastCrossSectionLine) crossSection, (Double) nextKm, (Double) prevKm); + } + else { + return new Lines.LineData(new double[][] {}, 0d,0d); + } + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + CrossSectionWaterLineFacet copy = new CrossSectionWaterLineFacet( + this.getIndex(), + this.description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DataFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,107 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +public class DataFacet +extends BlackboardDataFacet +{ + protected ComputeType type; + protected String hash; + protected String stateId; + + + /** Trivial constructor. */ + public DataFacet() { + } + + /** + * Defaults to ADVANCE Compute type. + * @param name Name of the facet. + * @param description maybe localized description of the facet. + */ + public DataFacet(String name, String description) { + this(name, description, ComputeType.ADVANCE); + } + + + public DataFacet(String name, String description, ComputeType type) { + this(name, description, type, null); + } + + + public DataFacet( + String name, + String description, + ComputeType type, + String hash + ) { + super(name, description); + this.type = type; + this.hash = hash; + } + + + public DataFacet( + String name, + String description, + ComputeType type, + String hash, + String stateId + ) { + super(name, description); + this.type = type; + this.hash = hash; + this.stateId = stateId; + } + + + public DataFacet( + int index, + String name, + String description, + ComputeType type, + String hash, + String stateId + ) { + super(index, name, description); + this.type = type; + this.hash = hash; + this.stateId = stateId; + } + + + /** + * Return computation result. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + FLYSArtifact flys = (FLYSArtifact)artifact; + String theHash = (hash != null) ? hash : flys.hash(); + + return (stateId != null && stateId.length() > 0) + ? flys.compute(context, theHash, stateId, type, false) + : flys.compute(context, theHash, type, false); + } + + + /** + * Return a deep copy. + */ + @Override + public Facet deepCopy() { + DataFacet copy = new DataFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DateRange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,51 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; +import java.util.Date; + +public class DateRange +implements Serializable +{ + private static final long serialVersionUID = -2553914795388094818L; + + protected Date from; + protected Date to; + + public DateRange(Date from, Date to) { + this.from = from; + this.to = to; + } + + public Date getFrom() { + return from; + } + + public void setFrom(Date from) { + this.from = from; + } + + public Date getTo() { + return to; + } + + public void setTo(Date to) { + this.to = to; + } + + private static final boolean equalDates(Date a, Date b) { + if (a == null && b != null) return false; + if (a != null && b == null) return false; + if (a == null) return true; + return a.equals(b); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof DateRange)) { + return false; + } + DateRange o = (DateRange)other; + return equalDates(from, o.from) && equalDates(to, o.to); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DifferenceCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,68 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet with the curve of a subtraction of two waterlevel-lines. + * TODO inherit directly from DataFacet? Check whether this Facet is obsolete. + */ +public class DifferenceCurveFacet extends WaterlevelFacet { + + private static Logger logger = Logger.getLogger(DifferenceCurveFacet.class); + + + public DifferenceCurveFacet() { + } + + public DifferenceCurveFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + + ) { + super(index, name, description, type, stateID, hash); + } + + /** + * Get difference curve data. + * @return a WKms at given index. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult res = (CalculationResult) + winfo.compute(context, hash, stateId, type, false); + + WKms [] wkms = (WKms [])res.getData(); + + WKms result = wkms[index]; + logger.debug("Got difference curve data (" + result.getName() + + ") at index: " + index); + + return result; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + WaterlevelFacet copy = new DifferenceCurveFacet(); + copy.set(this); + copy.type = type; + copy.stateId = stateId; + copy.hash = hash; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,235 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; + +import java.io.Serializable; + +import org.hibernate.Session; +import org.hibernate.Query; + +import org.apache.log4j.Logger; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.DischargeTableValue; + +import gnu.trove.TDoubleArrayList; + +/** Documentation goes here. */ +public class DischargeTables +implements Serializable +{ + /** Private logger. */ + private static Logger log = Logger.getLogger(DischargeTables.class); + + public static final double DEFAULT_SCALE = 100.0; + + public static final int MASTER = 0; + + protected List<String> gaugeNames; + + protected String riverName; + + protected double scale; + + protected int kind; + + protected Map<String, double [][]> values; + + public DischargeTables() { + } + + public DischargeTables(String riverName, String gaugeName) { + this(riverName, gaugeName, MASTER); + } + + public DischargeTables(String riverName, String gaugeName, int kind) { + this(riverName, new String [] { gaugeName }, kind); + } + + public DischargeTables(String riverName, String [] gaugeNames) { + this(riverName, gaugeNames, MASTER); + } + + public DischargeTables(String riverName, String [] gaugeNames, int kind) { + this(riverName, Arrays.asList(gaugeNames), kind); + } + + public DischargeTables( + String riverName, + List<String> gaugeNames, + int kind + ) { + scale = Double.NaN; + this.kind = kind; + this.riverName = riverName; + this.gaugeNames = gaugeNames; + } + + public double [][] getFirstTable() { + return getFirstTable(DEFAULT_SCALE); + } + + public double [][] getFirstTable(double scale) { + Map<String, double [][]> values = getValues(scale); + for (double [][] table: values.values()) { + return table; + } + return null; + } + + public Map<String, double [][]> getValues() { + return getValues(DEFAULT_SCALE); + } + + public Map<String, double [][]> getValues(double scale) { + if (values == null || scale != this.scale) { + values = loadValues(scale); + this.scale = scale; + } + return values; + } + + /** + * Returns mapping of gauge name to values. + */ + protected Map<String, double [][]> loadValues(double scale) { + Map<String, double [][]> values = new HashMap<String, double [][]>(); + + Session session = SessionHolder.HOLDER.get(); + + Query gaugeQuery = session.createQuery( + "from Gauge where name=:gauge and river.name=:river"); + gaugeQuery.setParameter("river", riverName); + + for (String gaugeName: gaugeNames) { + gaugeQuery.setParameter("gauge", gaugeName); + List<Gauge> gauges = gaugeQuery.list(); + if (gauges.isEmpty()) { + log.warn( + "no gauge '"+gaugeName+"' at river '"+riverName+"'"); + continue; + } + Gauge gauge = gauges.get(0); + + List<DischargeTable> tables = gauge.getDischargeTables(); + + if (tables.isEmpty()) { + log.warn( + "no discharge table for gauge '" + gaugeName + "'"); + continue; + } + + // TODO: Filter by time interval + DischargeTable table = tables.get(0); + + double [][] vs = loadDischargeTableValues(table, scale); + + values.put(gaugeName, vs); + } + + return values; + } + + + /** + * @param table The discharge table + * @param scale The scale factor to adjust W and Q values. + * + * @return the values of a discharge table. + */ + public static double[][] loadDischargeTableValues( + DischargeTable table, + double scale + ) { + List<DischargeTableValue> dtvs = table.getDischargeTableValues(); + + final double [][] vs = new double[2][dtvs.size()]; + + int idx = 0; + for (DischargeTableValue dtv: dtvs) { + double q = dtv.getQ().doubleValue(); + vs[0][idx] = q * scale; + vs[1][idx] = dtv.getW().doubleValue() * scale; + ++idx; + } + + return vs; + } + + private static final double EPSILON = 1e-5; + + private static final boolean epsEquals(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + + private static final boolean between(double a, double b, double x) { + if (a > b) { double t = a; a = b; b = t; } + return x > a && x < b; + } + + public static double [] getQsForW(double [][] values, double w) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("getQsForW: W = " + w); + } + + double [] qs = values[0]; + double [] ws = values[1]; + + int N = Math.min(qs.length, ws.length); + + if (N == 0) { + if (debug) { + log.debug("Q(" + w + ") = []"); + } + return new double [0]; + } + + TDoubleArrayList outQs = new TDoubleArrayList(); + + if (epsEquals(ws[0], w)) { + outQs.add(qs[0]); + } + + for (int i = 1; i < N; ++i) { + if (epsEquals(ws[i], w)) { + outQs.add(qs[i]); + } + else if (between(ws[i-1], ws[i], w)) { + double w1 = ws[i-1]; + double w2 = ws[i]; + double q1 = qs[i-1]; + double q2 = qs[i]; + + // q1 = m*w1 + b + // q2 = m*w2 + b + // q2 - q1 = m*(w2 - w1) + // m = (q2 - q1)/(w2 - w1) # w2 != w1 + // b = q1 - m*w1 + // w1 != w2 + + double m = (q2 - q1)/(w2 - w1); + double b = q1 - m*w1; + double q = w*m + b; + + outQs.add(q); + } + } + + double [] result = outQs.toNativeArray(); + + if (debug) { + log.debug("Q(" + w + ") = " + Arrays.toString(result)); + } + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,98 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Data of a duration curve. + */ +public class DurationCurveFacet extends DefaultFacet { + + private static Logger logger = Logger.getLogger(DurationCurveFacet.class); + + /** Blackboard data provider key for durationcurve (wqday) data. */ + public static String BB_DURATIONCURVE = "durationcurve"; + + /** Blackboard data provider key for km of durationcurve. */ + public static String BB_DURATIONCURVE_KM = "durationcurve.km"; + + public DurationCurveFacet() { + } + + public DurationCurveFacet(String name, String description) { + super(0, name, description); + } + + + /** + * Expose state computation from WINFOArtifact. + */ + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for duration curve data"); + + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult cr = (CalculationResult)winfo.compute( + context, ComputeType.ADVANCE, false); + + return cr.getData(); + } + + + @Override + public List getStaticDataProviderKeys(Artifact art) { + List list = new ArrayList(); + list.add(BB_DURATIONCURVE); + list.add(BB_DURATIONCURVE_KM); + return list; + } + + + /** + * Can provide whatever getData returns and additionally the location. + * @param key will respond on BB_DURATIONCURVE +KM + * @param param ignored + * @param context ignored + * @return whatever getData delivers or location. + */ + @Override + public Object provideBlackboardData(Artifact artifact, + Object key, + Object param, + CallContext context + ) { + if (key.equals(BB_DURATIONCURVE)) { + return getData(artifact, context); + } + else if (key.equals(BB_DURATIONCURVE_KM)) { + return ((FLYSArtifact)artifact).getDataAsString("ld_locations"); + } + else { + return null; + } + } + + + /** Create a deep copy. */ + @Override + public Facet deepCopy() { + DurationCurveFacet copy = new DurationCurveFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/EmptyFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,33 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +public class EmptyFacet +extends DefaultFacet +{ + /** Trivial constructor. */ + public EmptyFacet() { + super(0, "empty.facet", "empty.facet"); + } + + @Override + public Object getData(Artifact artifact, CallContext context) { + return null; + } + + + /** + * Return a deep copy. + */ + @Override + public Facet deepCopy() { + EmptyFacet copy = new EmptyFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,295 @@ +package de.intevation.flys.artifacts.model; + +/** 'Types' of facets. */ +public interface FacetTypes { + + public class IS { + public static boolean WQ_KM(String type) { + return type.equals(DISCHARGE_LONGITUDINAL_W) + || type.equals(LONGITUDINAL_W); + } + public static boolean W_KM(String type) { + return type.equals(STATIC_WKMS) + || type.equals(HEIGHTMARKS_POINTS) + || WQ_KM(type); + } + public static boolean AREA(String type) { + return type.equals(AREA) + || type.equals(CROSS_SECTION_AREA) + || type.equals(LONGITUDINAL_SECTION_AREA); + } + public static boolean W(String type) { + return type.equals(LONGITUDINAL_W) + || type.equals(DISCHARGE_LONGITUDINAL_W) + || type.equals(DURATION_W) + || type.equals(STATIC_WKMS) + || type.equals(STATIC_WQKMS_W); + } + public static boolean Q(String type) { + return type.equals(LONGITUDINAL_Q) + || type.equals(DISCHARGE_LONGITUDINAL_Q) + || type.equals(DURATION_Q) + || type.equals(STATIC_WQKMS_Q); + } + public static boolean V(String type) { + return type.equals(FLOW_VELOCITY_MAINCHANNEL) + || type.equals(FLOW_VELOCITY_TOTALCHANNEL); + } + public static boolean T(String type) { + return type.equals(FLOW_VELOCITY_TAU); + } + public static boolean H(String type) { + return type.equals(MIDDLE_BED_HEIGHT_SINGLE) + || type.equals(MIDDLE_BED_HEIGHT_EPOCH); + } + public static boolean MANUALPOINTS(String type) { + return type.endsWith("manualpoints"); + } + public static boolean MANUALLINE(String type) { + return type.endsWith("manualline"); + } + public static boolean SQ_CURVE(String type) { + if (type.equals(SQ_A_CURVE) + || type.equals(SQ_B_CURVE) + || type.equals(SQ_C_CURVE) + || type.equals(SQ_D_CURVE) + || type.equals(SQ_E_CURVE) + || type.equals(SQ_F_CURVE) + || type.equals(SQ_A_OUTLIER_CURVE) + || type.equals(SQ_B_OUTLIER_CURVE) + || type.equals(SQ_C_OUTLIER_CURVE) + || type.equals(SQ_D_OUTLIER_CURVE) + || type.equals(SQ_E_OUTLIER_CURVE) + || type.equals(SQ_F_OUTLIER_CURVE) + ) + { + return true; + } + + return false; + } + public static boolean SQ_MEASUREMENT(String type) { + if (type.equals(SQ_A_MEASUREMENT) + || type.equals(SQ_B_MEASUREMENT) + || type.equals(SQ_C_MEASUREMENT) + || type.equals(SQ_D_MEASUREMENT) + || type.equals(SQ_E_MEASUREMENT) + || type.equals(SQ_F_MEASUREMENT) + || type.equals(SQ_A_OUTLIER_MEASUREMENT) + || type.equals(SQ_B_OUTLIER_MEASUREMENT) + || type.equals(SQ_C_OUTLIER_MEASUREMENT) + || type.equals(SQ_D_OUTLIER_MEASUREMENT) + || type.equals(SQ_E_OUTLIER_MEASUREMENT) + || type.equals(SQ_F_OUTLIER_MEASUREMENT) + ) + { + return true; + } + + return false; + } + public static boolean SQ_OUTLIER(String type) { + if (type.equals(SQ_A_OUTLIER) + || type.equals(SQ_B_OUTLIER) + || type.equals(SQ_C_OUTLIER) + || type.equals(SQ_D_OUTLIER) + || type.equals(SQ_E_OUTLIER) + || type.equals(SQ_F_OUTLIER)) + { + return true; + } + + return false; + } + }; + + public enum ChartType { + LS("longitudinal_section"), + CS("cross_section"), + DLS("discharge_longitudinal_section"), + CDC("computed_discharge_curve"), + DUC("duration_curve"), + DIC("discharge_curve"), + RC("reference_curve"), + RCN("reference_curve_normalized"), + WD("wdifferences"), + HD("historical_discharge"); + + private String chartTypeString; + + ChartType(String description) { + this.chartTypeString = description; + } + + public String toString() { + return chartTypeString; + } + } + + String AREA = "area"; + String CROSS_SECTION_AREA = "cross_section.area"; + String LONGITUDINAL_SECTION_AREA = "longitudinal_section.area"; + + String FLOODMAP_WSPLGEN = "floodmap.wsplgen"; + String FLOODMAP_BARRIERS = "floodmap.barriers"; + String FLOODMAP_USERSHAPE = "floodmap.usershape"; + String FLOODMAP_RIVERAXIS = "floodmap.riveraxis"; + String FLOODMAP_WMSBACKGROUND = "floodmap.wmsbackground"; + String FLOODMAP_KMS = "floodmap.kms"; + String FLOODMAP_QPS = "floodmap.qps"; + String FLOODMAP_HWS = "floodmap.hws"; + String FLOODMAP_HYDR_BOUNDARY = "floodmap.hydr_boundaries"; + String FLOODMAP_HYDR_BOUNDARY_POLY = "floodmap.hydr_boundaries_poly"; + String FLOODMAP_CATCHMENT = "floodmap.catchment"; + String FLOODMAP_FLOODPLAIN = "floodmap.floodplain"; + String FLOODMAP_LINES = "floodmap.lines"; + String FLOODMAP_BUILDINGS = "floodmap.buildings"; + String FLOODMAP_FIXPOINTS = "floodmap.fixpoints"; + String FLOODMAP_FLOODMAPS = "floodmap.floodmaps"; + String FLOODMAP_GAUGE_LOCATION = "floodmap.gauge_location"; + String FLOODMAP_EXTERNAL_WMS = "floodmap.externalwms"; + + String DISCHARGE_LONGITUDINAL_W = "discharge_longitudinal_section.w"; + String DISCHARGE_LONGITUDINAL_Q = "discharge_longitudinal_section.q"; + String DISCHARGE_LONGITUDINAL_C = "discharge_longitudinal_section.c"; + + String LONGITUDINAL_W = "longitudinal_section.w"; + String LONGITUDINAL_Q = "longitudinal_section.q"; + String LONGITUDINAL_ANNOTATION = "longitudinal_section.annotations"; + String LONGITUDINAL_MANUALPOINTS = "longitudinal_section.manualpoints"; + + String W_DIFFERENCES = "w_differences"; + + String COMPUTED_DISCHARGE_Q = "computed_discharge_curve.q"; + String COMPUTED_DISCHARGE_MAINVALUES_Q = "computed_discharge_curve.mainvalues.q"; + String COMPUTED_DISCHARGE_MAINVALUES_W = "computed_discharge_curve.mainvalues.w"; + + String MAINVALUES_Q = "mainvalues.q"; + String MAINVALUES_W = "mainvalues.w"; + + String CROSS_SECTION = "cross_section"; + String CROSS_SECTION_WATER_LINE = "cross_section_water_line"; + + String HYK = "hyk"; + + String DISCHARGE_CURVE = "discharge_curve.curve"; + + String DURATION_W = "duration_curve.w"; + String DURATION_Q = "duration_curve.q"; + String DURATION_MAINVALUES_Q = "duration_curve.mainvalues.q"; + + String MANUALPOINTS = "manualpoints"; + String MANUALLINE = "manualline"; + + String QSECTOR = "qsectors"; + + String STATIC_WQ = "other.wq"; + String STATIC_WQ_ANNOTATIONS = "other.wq.annotations"; + String STATIC_WKMS = "other.wkms"; + String STATIC_WQKMS = "other.wqkms"; + String STATIC_WQKMS_W = "other.wqkms.w"; + String STATIC_WQKMS_Q = "other.wqkms.q"; + String STATIC_WKMS_INTERPOL = "other.wkms.interpol"; + + String HEIGHTMARKS_POINTS = "heightmarks_points"; + + String CSV = "csv"; + String WST = "wst"; + String AT = "at"; + String PDF = "pdf"; + + String REPORT = "report"; + + String HISTORICAL_DISCHARGE_Q = "historical_discharge.historicalq"; + String HISTORICAL_DISCHARGE_Q_DIFF = "historical_discharge.historicalq.diff"; + + String REFERENCE_CURVE = "reference_curve"; + String REFERENCE_CURVE_NORMALIZED = "reference_curve_normalized"; + + String FLOW_VELOCITY_MAINCHANNEL = "flow_velocity.mainchannel"; + String FLOW_VELOCITY_TOTALCHANNEL = "flow_velocity.totalchannel"; + String FLOW_VELOCITY_TAU = "flow_velocity.tau"; + String FLOW_VELOCITY_ANNOTATION = "flow_velocity.annotation"; + + String MIDDLE_BED_HEIGHT_SINGLE = "bedheight_middle.single"; + String MIDDLE_BED_HEIGHT_EPOCH = "bedheight_middle.epoch"; + String MIDDLE_BED_HEIGHT_ANNOTATION = "bedheight_middle.annotation"; + + String BED_QUALITY_POROSITY_TOPLAYER = "bed_longitudinal_section.porosity_toplayer"; + String BED_QUALITY_POROSITY_SUBLAYER = "bed_longitudinal_section.porosity_sublayer"; + String BED_QUALITY_BED_DIAMETER_TOPLAYER = "bed_longitudinal_section.bed_diameter_toplayer"; + String BED_QUALITY_BED_DIAMETER_SUBLAYER = "bed_longitudinal_section.bed_diameter_sublayer"; + String BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER = "bed_longitudinal_section.sediment_density_toplayer"; + String BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER = "bed_longitudinal_section.sediment_density_sublayer"; + String BED_QUALITY_BEDLOAD_DIAMETER = "bed_longitudinal_section.bedload_diameter"; + + String SQ_OVERVIEW = "sq_overview"; + + String SQ_A_CURVE = "sq_a_curve"; + String SQ_A_MEASUREMENT = "sq_a_measurement"; + String SQ_A_OUTLIER = "sq_a_outlier"; + String SQ_A_OUTLIER_CURVE = "sq_a_outlier_curve"; + String SQ_A_OUTLIER_MEASUREMENT = "sq_a_outlier_measurement"; + + String SQ_B_CURVE = "sq_b_curve"; + String SQ_B_MEASUREMENT = "sq_b_measurement"; + String SQ_B_OUTLIER = "sq_b_outlier"; + String SQ_B_OUTLIER_CURVE = "sq_b_outlier_curve"; + String SQ_B_OUTLIER_MEASUREMENT = "sq_b_outlier_measurement"; + + String SQ_C_CURVE = "sq_c_curve"; + String SQ_C_MEASUREMENT = "sq_c_measurement"; + String SQ_C_OUTLIER = "sq_c_outlier"; + String SQ_C_OUTLIER_CURVE = "sq_c_outlier_curve"; + String SQ_C_OUTLIER_MEASUREMENT = "sq_c_outlier_measurement"; + + String SQ_D_CURVE = "sq_d_curve"; + String SQ_D_MEASUREMENT = "sq_d_measurement"; + String SQ_D_OUTLIER = "sq_d_outlier"; + String SQ_D_OUTLIER_CURVE = "sq_d_outlier_curve"; + String SQ_D_OUTLIER_MEASUREMENT = "sq_d_outlier_measurement"; + + String SQ_E_CURVE = "sq_e_curve"; + String SQ_E_MEASUREMENT = "sq_e_measurement"; + String SQ_E_OUTLIER = "sq_e_outlier"; + String SQ_E_OUTLIER_CURVE = "sq_e_outlier_curve"; + String SQ_E_OUTLIER_MEASUREMENT = "sq_e_outlier_curve_measurement"; + + String SQ_F_CURVE = "sq_f_curve"; + String SQ_F_MEASUREMENT = "sq_f_measurement"; + String SQ_F_OUTLIER = "sq_f_outlier"; + String SQ_F_OUTLIER_CURVE = "sq_f_outlier_curve"; + String SQ_F_OUTLIER_MEASUREMENT = "sq_f_outlier_measurement"; + + String RELATIVE_POINT = "relativepoint"; + + String FIX_ANALYSIS_EVENTS_DWT = "fix_analysis_events_dwt"; + String FIX_ANALYSIS_EVENTS_LS = "fix_analysis_events_ls"; + String FIX_ANALYSIS_EVENTS_WQ = "fix_analysis_events_wq"; + + String FIX_REFERENCE_EVENTS_DWT = "fix_reference_events_dwt"; + String FIX_REFERENCE_EVENTS_LS = "fix_reference_events_ls"; + String FIX_REFERENCE_EVENTS_WQ = "fix_reference_events_wq"; + + String FIX_SECTOR_AVERAGE_DWT = "fix_sector_average_dwt"; + String FIX_SECTOR_AVERAGE_LS = "fix_sector_average_ls"; + String FIX_SECTOR_AVERAGE_WQ = "fix_sector_average_wq"; + String FIX_SECTOR_AVERAGE_LS_DEVIATION = "fix_sector_average_ls_deviation"; + + String FIX_WQ_CURVE = "fix_wq_curve"; + String FIX_OUTLIER = "fix_outlier"; + + String FIX_ANALYSIS_PERIODS_DWT = "fix_analysis_periods_dwt"; + String FIX_ANALYSIS_PERIODS_LS = "fix_analysis_periods_ls"; + String FIX_ANALYSIS_PERIODS_WQ = "fix_analysis_periods_wq"; + + String FIX_DERIVATE = "fix_derivate"; + + String FIX_DEVIATION_DWT = "fix_deviation_dwt"; + String FIX_DEVIATION_LS = "fix_deviation_ls"; + + String FIX_PARAMETERS = "fix_parameters"; + + String STATIC_BEDHEIGHT = "static_bedheight"; +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionChunk.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,83 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.util.Collections; + +import java.io.Serializable; + +import de.intevation.flys.model.CrossSection; + +import de.intevation.flys.model.FastCrossSectionLine; + +import org.apache.log4j.Logger; + +public class FastCrossSectionChunk +implements Serializable +{ + private static Logger log = Logger.getLogger(FastCrossSectionChunk.class); + + public static final String PREFIX = "FCSC:"; + public static final double KM_RANGE = 1.0; + + protected double startKm; + protected int crossSectionId; + + protected List<FastCrossSectionLine> crossSectionLines; + + public FastCrossSectionChunk() { + } + + public FastCrossSectionChunk(CrossSection cs, double km) { + + crossSectionId = cs.getId(); + startKm = Math.floor(km); + double stopKm = startKm + KM_RANGE; + + long startTime = System.currentTimeMillis(); + + crossSectionLines = cs.getFastLines(startKm, stopKm); + + long stopTime = System.currentTimeMillis(); + + if (log.isDebugEnabled()) { + log.debug("Fetching cross section lines took " + + (float)(stopTime-startTime)/1000f + " secs."); + } + } + + public FastCrossSectionLine getCrossSectionLine(double km) { + FastCrossSectionLine key = new FastCrossSectionLine(km); + int pos = Collections.binarySearch( + crossSectionLines, key, FastCrossSectionLine.KM_CMP); + return pos < 0 ? null : crossSectionLines.get(pos); + } + + public static String createHashKey(CrossSection cs, double km) { + return PREFIX + cs.getId() + ":" + (int)Math.floor(km); + } + + public String getHashKey() { + return PREFIX + crossSectionId + ":" + (int)Math.floor(startKm); + } + + public double getStartKm() { + return startKm; + } + + public void setStartKm(double startKm) { + this.startKm = startKm; + } + + public double getStopKm() { + return startKm + KM_RANGE; + } + + public int getCrossSectionId() { + return crossSectionId; + } + + public void setCrossSectionId(int crossSectionId) { + this.crossSectionId = crossSectionId; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLineFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,69 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.model.CrossSection; + +import de.intevation.flys.model.FastCrossSectionLine; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class FastCrossSectionLineFactory +{ + private static Logger log = + Logger.getLogger(FastCrossSectionLineFactory.class); + + public static final String CACHE_NAME = "fast-cross-section-lines"; + + private FastCrossSectionLineFactory() { + } + + public static FastCrossSectionLine getCrossSectionLine( + CrossSection cs, + double km + ) { + Cache cache = CacheFactory.getCache(CACHE_NAME); + + boolean debug = log.isDebugEnabled(); + + if (cache == null) { + if (debug) { + log.debug("No cross section chunk cache configured."); + } + List<FastCrossSectionLine> lines = cs.getFastLines(km, km); + return lines.isEmpty() ? null : lines.get(0); + } + + String cacheKey = FastCrossSectionChunk.createHashKey(cs, km); + + Element element = cache.get(cacheKey); + + FastCrossSectionChunk fcsc; + + if (element != null) { + if (debug) { + log.debug("Found cross section chunk in cache id: " + + cs.getId() + " km: " + km); + } + + fcsc = (FastCrossSectionChunk)element.getValue(); + } + else { + if (debug) { + log.debug("Not found cross section chunk in cache id: " + + cs.getId() + " km: " + km + " -> loading"); + } + fcsc = new FastCrossSectionChunk(cs, km); + element = new Element(cacheKey, fcsc); + cache.put(element); + } + + return fcsc.getCrossSectionLine(km); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,62 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.Linear; + +import java.util.Arrays; + +import java.io.Serializable; + +public class FixingsColumn +implements Serializable +{ + protected double [] kms; + protected double [] ws; + + protected QRangeTree qs; + + public FixingsColumn() { + } + + public FixingsColumn( + double [] kms, + double [] ws, + QRangeTree qs + ) { + this.kms = kms; + this.ws = ws; + this.qs = qs; + } + + public boolean getW(double km, double [] w) { + return getW(km, w, 0); + } + + public boolean getW(double km, double [] w, int index) { + + if (kms.length == 0 || km < kms[0] || km > kms[kms.length-1]) { + w[index] = Double.NaN; + return true; + } + + int idx = Arrays.binarySearch(kms, km); + + if (idx >= 0) { + w[index] = ws[idx]; + return true; + } + + idx = -idx - 1; + + w[index] = Linear.linear(km, kms[idx-1], kms[idx], ws[idx-1], ws[idx]); + return false; + } + + public double getQ(double km) { + return qs.findQ(km); + } + + public QRangeTree getQRanges() { + return qs; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.hibernate.Session; +import org.hibernate.SQLQuery; + +import org.hibernate.type.StandardBasicTypes; + +import org.apache.log4j.Logger; + +public class FixingsColumnFactory +{ + private static Logger log = Logger.getLogger(FixingsColumnFactory.class); + + public static final String CACHE_NAME = "fixings-columns"; + + public static final String SQL_COLUMN_WS = + "SELECT wcv.position AS km, wcv.w AS w " + + "FROM wst_column_values wcv " + + "WHERE wst_column_id = :column_id " + + "ORDER by wcv.position"; + + public static final String SQL_COLUMN_QS = + "SELECT wqr.q AS q, r.a AS a, r.b AS b " + + "FROM wst_column_q_ranges wcqr " + + "JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id " + + "JOIN ranges r ON wqr.range_id = r.id " + + "WHERE wcqr.wst_column_id = :column_id ORDER by r.a"; + + public static final FixingsColumnFactory INSTANCE = + new FixingsColumnFactory(); + + private FixingsColumnFactory() { + } + + public static FixingsColumnFactory getInstance() { + return INSTANCE; + } + + public FixingsColumn getColumnData(Fixing.Column column) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("FixingsColumnFactory.getColumnData"); + } + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + if (debug) { + log.debug("Cache unconfigured."); + } + return getUncached(column); + } + + Integer cacheKey = Integer.valueOf(column.getId()); + Element element = cache.get(cacheKey); + + if (element != null) { + if (debug) { + log.debug("Column " + cacheKey + " found in cache."); + } + return (FixingsColumn)element.getValue(); + } + else { + FixingsColumn result = getUncached(column); + if (result != null) { + if (debug) { + log.debug("Store column " + cacheKey + " into cache."); + } + cache.put(new Element(cacheKey, result)); + } + return result; + } + } + + protected FixingsColumn getUncached(Fixing.Column column) { + Session session = SessionHolder.HOLDER.get(); + + SQLQuery sqlQuery = session.createSQLQuery(SQL_COLUMN_WS) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("w", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("column_id", column.getId()); + + List<Object []> results = sqlQuery.list(); + + if (results.isEmpty()) { + return null; + } + + double [] kms = new double[results.size()]; + double [] ws = new double[kms.length]; + + for (int i = 0; i < kms.length; ++i) { + Object [] row = results.get(i); + kms[i] = ((Double)row[0]).doubleValue(); + ws [i] = ((Double)row[1]).doubleValue(); + } + + sqlQuery = session.createSQLQuery(SQL_COLUMN_QS) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("column_id", column.getId()); + + results = sqlQuery.list(); + + if (results.isEmpty()) { + return null; + } + + QRangeTree qs = new QRangeTree( + results, QRangeTree.WITHOUT_COLUMN, 0, results.size()); + + return new FixingsColumn(kms, ws, qs); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,247 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.DateFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; + +import de.intevation.flys.artifacts.model.FixingsOverview.IdFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.NotFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.OrFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.SectorRangeFilter; + +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class FixingsFilterBuilder +{ + private static Logger log = Logger.getLogger(FixingsFilterBuilder.class); + + protected Filter filter; + protected Range range; + + protected Document document; + + public FixingsFilterBuilder() { + } + + public FixingsFilterBuilder(Document document) { + this.document = document; + } + + public Filter getFilter() { + if (filter == null) { + filter = buildFilter(); + } + return filter; + } + + public Range getRange() { + if (range == null) { + range = buildRange(); + } + return range; + } + + public Document getDocument() { + return document; + } + + protected Range buildRange() { + + NodeList ranges = document.getElementsByTagName("range"); + + if (ranges.getLength() < 1) { + return FixingsOverview.FULL_EXTENT; + } + + Element range = (Element)ranges.item(0); + + String from = range.getAttribute("from").trim(); + String to = range.getAttribute("to" ).trim(); + + double start = -Double.MAX_VALUE; + double end = Double.MAX_VALUE; + + if (from.length() > 0) { + try { + start = Double.parseDouble(from); + } + catch (NumberFormatException nfe) { + log.warn("Invalid from value: " + from); + } + } + + if (to.length() > 0) { + try { + end = Double.parseDouble(to); + } + catch (NumberFormatException nfe) { + log.warn("Invalid to value: " + to); + } + } + + if (start > end) { + double t = start; + start = end; + end = t; + } + + return new Range(start, end); + } + + protected Filter buildFilter() { + NodeList filters = document.getElementsByTagName("filter"); + + return filters.getLength() < 1 + ? FixingsOverview.ACCEPT + : buildFilter((Element)filters.item(0)); + } + + protected static Filter buildFilter(Element root) { + List<Filter> filters = buildRecursiveFilter(root); + switch (filters.size()) { + case 0: return FixingsOverview.ACCEPT; + case 1: return filters.get(0); + default: return new AndFilter(filters); + } + } + + protected static final Date parseDate(String text) { + SimpleDateFormat format = + new SimpleDateFormat(FixingsOverview.DATE_FORMAT); + return format.parse(text, new ParsePosition(0)); + } + + protected static List<Filter> buildRecursiveFilter(Element root) { + List<Filter> filters = new ArrayList<Filter>(); + + NodeList children = root.getChildNodes(); + + for (int i = 0, N = children.getLength(); i < N; ++i) { + Node child = children.item(i); + if (child.getNodeType() != Node.ELEMENT_NODE) { + continue; + } + + Element element = (Element)child; + String name = element.getLocalName(); + + if ("and".equals(name)) { + filters.add(new AndFilter(buildRecursiveFilter(element))); + } + else if ("or".equals(name)) { + filters.add(new OrFilter(buildRecursiveFilter(element))); + } + else if ("not".equals(name)) { + List<Filter> childrenFilters = buildRecursiveFilter(element); + if (!childrenFilters.isEmpty()) { + filters.add(new NotFilter(childrenFilters.get(0))); + } + } + else if ("column".equals(name)) { + String cid = element.getAttribute("cid").trim(); + if (cid.length() > 0) { + try { + filters.add(new IdFilter(Integer.parseInt(cid))); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + } + } + } + else if ("columns".equals(name)) { + String cidsS = element.getAttribute("cids").trim(); + String [] parts = cidsS.split("\\s+"); + List<Integer> ids = new ArrayList<Integer>(); + for (String part: parts) { + try { + ids.add(Integer.valueOf(part)); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + } + } + int [] cids = new int[ids.size()]; + for (int j = 0; j < cids.length; ++j) { + cids[j] = ids.get(j); + } + filters.add(new IdsFilter(cids)); + } + else if ("date".equals(name)) { + String when = element.getAttribute("when").trim(); + if (when.length() > 0) { + Date date = parseDate(when); + if (date != null) { + filters.add(new DateFilter(date)); + } + } + } + else if ("date-range".equals(name)) { + String from = element.getAttribute("from").trim(); + String to = element.getAttribute("to" ).trim(); + if (from.length() > 0 && to.length() > 0) { + Date start = parseDate(from); + Date end = parseDate(to); + if (start != null && end != null) { + filters.add(new DateRangeFilter(start, end)); + } + } + } + else if ("sector-range".equals(name)) { + String from = element.getAttribute("from").trim(); + String to = element.getAttribute("to" ).trim(); + if (from.length() > 0 && to.length() > 0) { + try { + filters.add(new SectorRangeFilter( + Integer.parseInt(from), + Integer.parseInt(to))); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + } + } + } + else if ("sector".equals(name)) { + String value = element.getAttribute("value").trim(); + if (value.length() > 0) { + try { + filters.add(new SectorFilter(Integer.parseInt(value))); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + } + } + } + else if ("position".equals(name)) { + String km = element.getAttribute("km").trim(); + if (km.length() > 0) { + try { + filters.add(new KmFilter(Double.parseDouble(km))); + } + catch (NumberFormatException nfe) { + log.warn(nfe); + } + } + } + } + + return filters; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,788 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.text.SimpleDateFormat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.type.StandardBasicTypes; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class FixingsOverview +implements Serializable +{ + private static Logger log = Logger.getLogger(FixingsOverview.class); + + public static final double EPSILON = 1e-2; + + public static final String DATE_FORMAT = "dd.MM.yyyy"; + + public static final String SQL_RIVER_ID = + "SELECT" + + " id AS river_id," + + " km_up " + + "FROM rivers " + + "WHERE" + + " name = :name"; + + public static final String SQL_FIXINGS = + "SELECT" + + " id AS wst_id," + + " description " + + "FROM wsts " + + "WHERE" + + " river_id = :river_id AND kind = 2"; + + public static final String SQL_FIXING_COLUMNS = + "SELECT" + + " wc.id AS wst_column_id," + + " ti.start_time AS start_time," + + " wc.name AS name " + + "FROM wst_columns wc" + + " JOIN time_intervals ti ON wc.time_interval_id = ti.id " + + "WHERE" + + " wc.wst_id = :wst_id " + + "ORDER BY position"; + + public static final String SQL_FIXING_COLUMN_Q_RANGES = + "SELECT" + + " wqr.q AS q," + + " r.a AS start_km," + + " r.b AS stop_km " + + "FROM wst_column_q_ranges wcqr" + + " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" + + " JOIN ranges r ON wqr.range_id = r.id " + + "WHERE" + + " wcqr.wst_column_id = :column_id " + + "ORDER BY r.a"; + + public static final String SQL_FIXING_COLUMN_KM_RANGE = + "SELECT" + + " MIN(position) AS start_km," + + " MAX(position) AS stop_km " + + "FROM" + + " wst_column_values " + + "WHERE" + + " wst_column_id = :column_id"; + + + public static class QRange extends Range { + + protected double q; + + public QRange() { + } + + public QRange(double start, double end, double q) { + super(start, end); + this.q = q; + } + } // class QRange + + public static class SectorRange extends Range { + + protected int sector; + + public SectorRange() { + } + + public SectorRange(SectorRange other) { + start = other.start; + end = other.end; + sector = other.sector; + } + + public SectorRange(Range range) { + super(range); + } + + public SectorRange(double start, double end, int sector) { + super(start, end); + this.sector = sector; + } + + public int getSector() { + return sector; + } + + public void setSector(int sector) { + this.sector = sector; + } + + public boolean enlarge(SectorRange other) { + if (sector == other.sector + && Math.abs(end-other.start) < FixingsOverview.EPSILON) { + end = other.end; + return true; + } + return false; + } + } // class SectorRange + + public static class Fixing implements Serializable { + + public static final Comparator<Column> DATE_CMP = + new Comparator<Column>() { + @Override + public int compare(Column a, Column b) { + return a.startTime.compareTo(b.startTime); + } + }; + + public interface Filter { + + boolean accept(Column column); + + } // interface Filter + + public class Column extends Range { + + protected int columnId; + protected Date startTime; + protected String name; + + protected List<SectorRange> sectors; + + public Column() { + } + + public Column(int columnId, Date startTime, String name) { + this.columnId = columnId; + this.startTime = startTime; + this.name = name; + + sectors = new ArrayList<SectorRange>(); + } + + public int getId() { + return columnId; + } + + public Fixing getFixing() { + return Fixing.this; + } + + public Date getStartTime() { + return startTime; + } + + public String getName() { + return name; + } + + public String getDescription() { + return Fixing.this.description + "/" + name; + } + + public List<SectorRange> getSectors() { + return sectors; + } + + public List<SectorRange> getSectors(Range range) { + + List<SectorRange> result = + new ArrayList<SectorRange>(sectors.size()); + + for (SectorRange src: sectors) { + SectorRange dst = new SectorRange(src); + if (range == null || dst.clip(range)) { + result.add(dst); + } + } + + return result; + } + + public int findQSector(double km) { + for (SectorRange sector: sectors) { + if (sector.inside(km)) { + return sector.getSector(); + } + } + return -1; + } + + public void buildSectors( + GaugeFinder gaugeFinder, + List<QRange> qRanges + ) { + for (QRange qRange: qRanges) { + for (GaugeRange gRange: gaugeFinder.getGauges()) { + SectorRange sector = new SectorRange(qRange); + if (!sector.clip(gRange)) { + continue; + } + sector.setSector(gRange.classify(qRange.q)); + + if (sectors.isEmpty() + || !sectors.get(sectors.size()-1).enlarge(sector)) { + sectors.add(sector); + } + } // for all gauges + } // for all Q ranges + } + + public void loadKmRange(SQLQuery query) { + query.setInteger("column_id", columnId); + + List<Object []> kms = query.list(); + + if (kms.isEmpty()) { + log.warn("No km range for column " + columnId + "."); + } + else { + Object [] obj = kms.get(0); + start = (Double)obj[0]; + end = (Double)obj[1]; + } + } + + public void loadQRanges( + SQLQuery query, + GaugeFinder gaugeFinder + ) { + query.setInteger("column_id", columnId); + List<Object []> list = query.list(); + + List<QRange> qRanges = new ArrayList<QRange>(list.size()); + + for (Object [] row: list) { + double q = (Double)row[0]; + double start = (Double)row[1]; + double end = (Double)row[2]; + QRange qRange = new QRange(start, end, q); + if (qRange.clip(this)) { + qRanges.add(qRange); + } + } + + buildSectors(gaugeFinder, qRanges); + } + } // class Column + + protected int wstId; + protected String description; + protected List<Column> columns; + + public Fixing() { + } + + public int getId() { + return wstId; + } + + public String getDescription() { + return description; + } + + public Fixing(int wstId, String description) { + this.wstId = wstId; + this.description = description; + columns = new ArrayList<Column>(); + } + + public void loadColumns(SQLQuery query) { + query.setInteger("wst_id", wstId); + List<Object []> list = query.list(); + for (Object [] row: list) { + int columnId = (Integer)row[0]; + Date startTime = (Date) row[1]; + String name = (String) row[2]; + columns.add(new Column(columnId, startTime, name)); + } + } + + public void loadColumnsKmRange(SQLQuery query) { + for (Column column: columns) { + column.loadKmRange(query); + } + } + + public void adjustExtent(Range extent) { + for (Column column: columns) { + extent.extend(column); + } + } + + public void loadColumnsQRanges( + SQLQuery query, + GaugeFinder gaugeFinder + ) { + for (Column column: columns) { + column.loadQRanges(query, gaugeFinder); + } + } + + public void addAllColumns( + List<Column> allColumns, + Range range, + Filter filter + ) { + for (Column column: columns) { + if ((range == null || column.intersects(range)) + && (filter == null || filter.accept(column))) { + allColumns.add(column); + } + } + } + } // class Fixing + + + protected String riverName; + protected int riverId; + protected boolean isKmUp; + protected List<Fixing> fixings; + protected Range extent; + + public FixingsOverview() { + fixings = new ArrayList<Fixing>(); + extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); + } + + public FixingsOverview(String riverName) { + this(); + this.riverName = riverName; + } + + protected boolean loadRiver(Session session) { + SQLQuery query = session.createSQLQuery(SQL_RIVER_ID) + .addScalar("river_id", StandardBasicTypes.INTEGER) + .addScalar("km_up", StandardBasicTypes.BOOLEAN); + + query.setString("name", riverName); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("No river '" + riverName + "' found."); + return false; + } + + Object [] row = list.get(0); + + riverId = (Integer)row[0]; + isKmUp = (Boolean)row[1]; + + return true; + } + + protected void loadFixings(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXINGS) + .addScalar("wst_id", StandardBasicTypes.INTEGER) + .addScalar("description", StandardBasicTypes.STRING); + + query.setInteger("river_id", riverId); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("River " + riverId + " has no fixings."); + // Its pretty fine to have no fixings. + } + + for (Object [] row: list) { + int wstId = (Integer)row[0]; + String description = (String) row[1]; + Fixing fixing = new Fixing(wstId, description); + fixings.add(fixing); + } + } + + protected void loadFixingsColumns(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS) + .addScalar("wst_column_id", StandardBasicTypes.INTEGER) + .addScalar("start_time", StandardBasicTypes.DATE) + .addScalar("name", StandardBasicTypes.STRING); + + for (Fixing fixing: fixings) { + fixing.loadColumns(query); + } + } + + protected void loadFixingsColumnsKmRange(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + for (Fixing fixing: fixings) { + fixing.loadColumnsKmRange(query); + } + } + + protected void loadFixingsColumnsQRanges( + Session session, + GaugeFinder gaugeFinder + ) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + for (Fixing fixing: fixings) { + fixing.loadColumnsQRanges(query, gaugeFinder); + } + } + + protected void adjustExtent() { + for (Fixing fixing: fixings) { + fixing.adjustExtent(extent); + } + } + + public boolean load(Session session) { + + if (!loadRiver(session)) { + return false; + } + + GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); + + GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp); + + if (gaugeFinder == null) { + return false; + } + + loadFixings(session); + loadFixingsColumns(session); + loadFixingsColumnsKmRange(session); + + adjustExtent(); + + loadFixingsColumnsQRanges(session, gaugeFinder); + + return true; + } + + public static final Range FULL_EXTENT = + new Range(-Double.MAX_VALUE, Double.MAX_VALUE); + + public static final Fixing.Filter ACCEPT = new Fixing.Filter() { + @Override + public boolean accept(Fixing.Column column) { + return true; + } + }; + + public static class NotFilter implements Fixing.Filter { + protected Fixing.Filter child; + + public NotFilter(Fixing.Filter child) { + this.child = child; + } + + @Override + public boolean accept(Fixing.Column column) { + return !child.accept(column); + } + } // class NotFilter + + public static abstract class ComponentFilter implements Fixing.Filter { + protected List<Fixing.Filter> children; + + public ComponentFilter() { + children = new ArrayList<Fixing.Filter>(); + } + + public ComponentFilter(List<Fixing.Filter> children) { + this.children = children; + } + + public ComponentFilter add(Fixing.Filter filter) { + children.add(filter); + return this; + } + } // class ComponentFilter + + public static class OrFilter extends ComponentFilter { + + public OrFilter() { + } + + public OrFilter(List<Fixing.Filter> children) { + super(children); + } + + @Override + public boolean accept(Fixing.Column column) { + for (Fixing.Filter child: children) { + if (child.accept(column)) { + return true; + } + } + return false; + } + } // class OrFilter + + public static class AndFilter extends ComponentFilter { + + public AndFilter() { + } + + public AndFilter(List<Fixing.Filter> children) { + super(children); + } + + @Override + public boolean accept(Fixing.Column column) { + for (Fixing.Filter child: children) { + if (!child.accept(column)) { + return false; + } + } + return true; + } + } // class AndFilter + + public static class IdFilter implements Fixing.Filter { + + protected int columnId; + + public IdFilter(int columnId) { + this.columnId = columnId; + } + + @Override + public boolean accept(Fixing.Column column) { + return column.getId() == columnId; + } + } // class IdFilter + + public static class IdsFilter implements Fixing.Filter { + + protected int [] columnIds; + + public IdsFilter(int [] columnIds) { + this.columnIds = columnIds; + } + + @Override + public boolean accept(Fixing.Column column) { + int cid = column.getId(); + for (int i = columnIds.length-1; i >= 0; --i) { + if (columnIds[i] == cid) { + return true; + } + } + return false; + } + } // class IdFilter + + public static class DateFilter implements Fixing.Filter { + + protected Date date; + + public DateFilter(Date date) { + this.date = date; + } + + @Override + public boolean accept(Fixing.Column column) { + return date.equals(column.getStartTime()); + } + } // class DateFilter + + public static class DateRangeFilter implements Fixing.Filter { + + protected Date start; + protected Date end; + + public DateRangeFilter(Date start, Date end) { + this.start = start; + this.end = end; + } + + @Override + public boolean accept(Fixing.Column column) { + Date date = column.getStartTime(); + return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; + } + } // class DateRangeFilter + + public static class SectorFilter implements Fixing.Filter { + + protected int sector; + + public SectorFilter(int sector) { + this.sector = sector; + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + if (s.getSector() == sector) { + return true; + } + } + return false; + } + } // class SectorFilter + + public static class SectorRangeFilter implements Fixing.Filter { + + protected int min; + protected int max; + + public SectorRangeFilter(int min, int max) { + this.min = Math.min(min, max); + this.max = Math.max(min, max); + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + int v = s.getSector(); + if (v >= min && v <= max) { + return true; + } + } + return false; + } + } // class SectorRangeFilter + + public static class KmFilter implements Fixing.Filter { + + protected double km; + + public KmFilter(double km) { + this.km = km; + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + if (s.inside(km)) { + return true; + } + } + return false; + } + } // class KmFilter + + public void generateOverview(Document document) { + generateOverview(document, FULL_EXTENT, ACCEPT); + } + + public List<Fixing.Column> filter(Range range, Fixing.Filter filter) { + List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); + + for (Fixing fixing: fixings) { + fixing.addAllColumns(allColumns, range, filter); + } + + Collections.sort(allColumns, Fixing.DATE_CMP); + + return allColumns; + } + + protected static Range realRange(List<Fixing.Column> columns) { + Range range = null; + for (Fixing.Column column: columns) { + if (range == null) { + range = new Range(column); + } + else { + range.extend(column); + } + } + return range; + } + + protected Element intersectingGauges(Document document, Range range) { + Element gauges = document.createElement("gauges"); + + if (range == null) { + return gauges; + } + + GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); + + GaugeFinder gf = gff.getGaugeFinder(riverId, isKmUp); + + if (gf == null) { + return gauges; + } + + for (GaugeRange gr: gf.getGauges()) { + if (gr.intersects(range)) { + Element gauge = document.createElement("gauge"); + gauge.setAttribute("from", String.valueOf(gr.getStart())); + gauge.setAttribute("to", String.valueOf(gr.getEnd())); + gauge.setAttribute("name", gr.getName()); + gauges.appendChild(gauge); + } + } + + return gauges; + } + + public void generateOverview( + Document document, + Range range, + Fixing.Filter filter + ) { + List<Fixing.Column> allColumns = filter(range, filter); + + Element fixingsElement = document.createElement("fixings"); + + Element riverElement = document.createElement("river"); + + riverElement.setAttribute("from", String.valueOf(extent.start)); + riverElement.setAttribute("to", String.valueOf(extent.end)); + riverElement.setAttribute("rid", String.valueOf(riverId)); + riverElement.setAttribute("name", riverName); + + fixingsElement.appendChild(riverElement); + + fixingsElement.appendChild( + intersectingGauges( + document, + realRange(allColumns))); + + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + + Element esE = document.createElement("events"); + + for (Fixing.Column column: allColumns) { + + List<SectorRange> sectors = column.getSectors(range); + + if (!sectors.isEmpty()) { + Element eE = document.createElement("event"); + eE.setAttribute("description", + String.valueOf(column.getDescription())); + eE.setAttribute("cid", String.valueOf(column.columnId)); + eE.setAttribute("date", df.format(column.startTime)); + + for (SectorRange sector: sectors) { + Element sE = document.createElement("sector"); + + sE.setAttribute("from", String.valueOf(sector.start)); + sE.setAttribute("to", String.valueOf(sector.end)); + sE.setAttribute("class", String.valueOf(sector.sector)); + + eE.appendChild(sE); + } + + esE.appendChild(eE); + } + } + + fixingsElement.appendChild(esE); + + document.appendChild(fixingsElement); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverviewFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import org.hibernate.Session; + +public class FixingsOverviewFactory +{ + private static Logger log = Logger.getLogger(FixingsOverviewFactory.class); + + public static final String CACHE_NAME = "fixings-overviews"; + + private FixingsOverviewFactory() { + } + + + public static FixingsOverview getOverview(String river) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Looking for fixings overview for river '" + river + "'"); + } + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + if (debug) { + log.debug("Cache not configured."); + } + return getUncached(river); + } + + String key = "fix-over-" + river; + + Element element = cache.get(key); + + if (element != null) { + if (debug) { + log.debug("Overview found in cache"); + } + return (FixingsOverview)element.getValue(); + } + + FixingsOverview overview = getUncached(river); + + if (overview != null) { + if (debug) { + log.debug("Store overview in cache."); + } + cache.put(new Element(key, overview)); + } + + return overview; + } + + public static FixingsOverview getUncached(String river) { + FixingsOverview overview = new FixingsOverview(river); + + Session session = SessionHolder.HOLDER.get(); + + return overview.load(session) ? overview : null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,169 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import de.intevation.artifacts.Artifact; + +import de.intevation.flys.artifacts.access.FlowVelocityAccess; + +import de.intevation.flys.artifacts.model.RiverFactory; + +import de.intevation.flys.model.DischargeZone; +import de.intevation.flys.model.FlowVelocityModel; +import de.intevation.flys.model.FlowVelocityModelValue; +import de.intevation.flys.model.River; + +import org.apache.log4j.Logger; + + +public class FlowVelocityCalculation extends Calculation { + + private static final Logger logger = + Logger.getLogger(FlowVelocityCalculation.class); + + + public CalculationResult calculate(FlowVelocityAccess access) { + logger.info("FlowVelocityCalculation.calculate"); + + int[] mainIds = access.getMainChannels(); + int[] totalIds = access.getTotalChannels(); + + if (logger.isDebugEnabled()) { + Artifact a = access.getArtifact(); + logger.debug("Artifact '" + a.identifier() + "' contains:"); + if (mainIds != null) { + logger.debug(" " + mainIds.length + " main channel ids"); + } + + if (totalIds != null) { + logger.debug(" " + totalIds.length + " total channel ids"); + } + } + + List<DischargeZone> zones = getDischargeZones(mainIds, totalIds); + List<FlowVelocityModel> models = getFlowVelocityModels(access, zones); + + return buildCalculationResult(access, models); + } + + + protected List<DischargeZone> getDischargeZones( + int[] mainIds, + int[] totalIds + ) { + List<DischargeZone> zones = new ArrayList<DischargeZone>(); + + if (mainIds != null) { + for (int id: mainIds) { + DischargeZone zone = DischargeZone.getDischargeZoneById(id); + + if (zone != null) { + zones.add(zone); + } + } + } + + if (totalIds != null) { + for (int id: totalIds) { + DischargeZone zone = DischargeZone.getDischargeZoneById(id); + + if (zone != null) { + zones.add(zone); + } + } + } + + return zones; + } + + + protected List<FlowVelocityModel> getFlowVelocityModels( + FlowVelocityAccess access, + List<DischargeZone> zones + ) { + String riverName = access.getRiver(); + if (riverName == null) { + logger.warn("No river name found"); + return Collections.<FlowVelocityModel>emptyList(); + } + + River river = RiverFactory.getRiver(riverName); + if (river == null) { + logger.warn("No such river: " + riverName); + return Collections.<FlowVelocityModel>emptyList(); + } + + List<FlowVelocityModel> models = new ArrayList<FlowVelocityModel>(); + + for (DischargeZone zone: zones) { + List<FlowVelocityModel> model = + FlowVelocityModel.getModels(river, zone); + + if (model != null) { + models.addAll(model); + } + } + + return models; + } + + + protected void prepareData( + FlowVelocityData data, + FlowVelocityModel model, + double kmLo, + double kmHi + ) { + List<FlowVelocityModelValue> values = + FlowVelocityModelValue.getValues(model, kmLo, kmHi); + + logger.debug("Found " + values.size() + " values for model."); + + for (FlowVelocityModelValue value: values) { + data.addKM(value.getStation().doubleValue()); + data.addQ(value.getQ().doubleValue()); + data.addVTotal(value.getTotalChannel().doubleValue()); + data.addVMain(value.getMainChannel().doubleValue()); + data.addTauMain(value.getShearStress().doubleValue()); + } + + DischargeZone zone = model.getDischargeZone(); + String lo = zone.getLowerDischarge(); + String hi = zone.getUpperDischarge(); + + if (lo.equals(hi)) { + data.setZone(lo); + } + else { + data.setZone(lo + " - " + hi); + } + } + + + protected CalculationResult buildCalculationResult( + FlowVelocityAccess access, + List<FlowVelocityModel> models + ) { + double kmLo = access.getLowerKM(); + double kmHi = access.getUpperKM(); + + logger.debug("Prepare data for km range: " + kmLo + " - " + kmHi); + + FlowVelocityData[] data = new FlowVelocityData[models.size()]; + + for (int i = 0, n = models.size(); i < n; i++) { + FlowVelocityData d = new FlowVelocityData(); + + prepareData(d, models.get(i), kmLo, kmHi); + + data[i] = d; + } + + logger.debug("Calculation contains " + data.length + " data items."); + + return new CalculationResult(data, this); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FlowVelocityData.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,115 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import gnu.trove.TDoubleArrayList; + + +public class FlowVelocityData implements Serializable { + + private TDoubleArrayList km; + private TDoubleArrayList vMain; + private TDoubleArrayList vTotal; + private TDoubleArrayList tauMain; + private TDoubleArrayList q; + private String zone; + + + protected FlowVelocityData() { + this.km = new TDoubleArrayList(); + this.vMain = new TDoubleArrayList(); + this.vTotal = new TDoubleArrayList(); + this.tauMain = new TDoubleArrayList(); + this.q = new TDoubleArrayList(); + } + + + public void addKM(double km) { + this.km.add(km); + } + + public double getKM(int idx) { + return km.get(idx); + } + + public void addVMain(double vMain) { + this.vMain.add(vMain); + } + + public double getVMain(int idx) { + return vMain.get(idx); + } + + public void addVTotal(double vTotal) { + this.vTotal.add(vTotal); + } + + public double getVTotal(int idx) { + return vTotal.get(idx); + } + + public void addTauMain(double tauMain) { + this.tauMain.add(tauMain); + } + + public double getTauMain(int idx) { + return tauMain.get(idx); + } + + public void addQ(double q) { + this.q.add(q); + } + + public double getQ(int idx) { + return q.get(idx); + } + + public void setZone(String zone) { + this.zone = zone; + } + + public String getZone() { + return zone; + } + + public int size() { + return km.size(); + } + + + public double[][] getMainChannelPoints() { + double[][] points = new double[2][size()]; + + for (int i = 0, n = size(); i < n; i++) { + points[0][i] = getKM(i); + points[1][i] = getVMain(i); + } + + return points; + } + + + public double[][] getTotalChannelPoints() { + double[][] points = new double[2][size()]; + + for (int i = 0, n = size(); i < n; i++) { + points[0][i] = getKM(i); + points[1][i] = getVTotal(i); + } + + return points; + } + + + public double[][] getTauPoints() { + double[][] points = new double[2][size()]; + + for (int i = 0, n = size(); i < n; i++) { + points[0][i] = getKM(i); + points[1][i] = getTauMain(i); + } + + return points; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FlowVelocityFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +/** + * Facet of a FlowVelocity curve. + */ +public class FlowVelocityFacet extends DataFacet { + + private static Logger logger = Logger.getLogger(FlowVelocityFacet.class); + + + public FlowVelocityFacet() { + // required for clone operation deepCopy() + } + + + public FlowVelocityFacet( + int idx, + String name, + String description, + ComputeType type, + String stateId, + String hash + ) { + super(idx, name, description, type, hash, stateId); + } + + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for flow velocity at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, false); + + FlowVelocityData[] data = (FlowVelocityData[]) res.getData(); + + return data[index]; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + FlowVelocityFacet copy = new FlowVelocityFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,86 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Access Discharge Curve of a gauge. + */ +public class GaugeDischargeFacet extends DataFacet { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(GaugeDischargeFacet.class); + + + public GaugeDischargeFacet() { + } + + + /** + * @param index Index translates to index of WQ-array. + * @param name Name of the facet. + * @param desc Description of the facet (visible in client). + */ + public GaugeDischargeFacet(int index, String name, String desc) { + super(index, name, desc, ComputeType.ADVANCE, null, + "state.gaugedischarge.init"); + } + + + public GaugeDischargeFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + + ) { + super(index, name, description, type, hash, stateID); + } + + + @Override + public Facet deepCopy() { + GaugeDischargeFacet copy = new GaugeDischargeFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } + + + /** + * @return wqkms corresponding to gauge of artifact and index of facet. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + if (logger.isDebugEnabled()) { + logger.debug("Get data for discharge curves at index: " + + index + " / stateId: " + stateId); + } + + if (stateId == null) { + logger.error("GaugeDischargeFacet.getData: stateId is null."); + } + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, true); + + WQKms[] discharge = (WQKms[]) res.getData(); + + return discharge[index]; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.type.StandardBasicTypes; + +public class GaugeFinder +implements Serializable +{ + private static Logger log = Logger.getLogger(GaugeFinder.class); + + public static final String SQL_DISCHARGE_SECTORS = + "SELECT" + + " g.id AS gauge_id," + + " nmv.name AS name," + + " CAST(mv.value AS NUMERIC(38,2)) AS value " + + "FROM gauges g" + + " JOIN main_values mv ON g.id = mv.gauge_id" + + " JOIN named_main_values nmv ON nmv.id = mv.named_value_id" + + " JOIN main_value_types mvt ON nmv.type_id = mvt.id " + + "WHERE" + + " mvt.name = 'Q' AND (" + + " nmv.name = 'MNQ' OR" + + " nmv.name LIKE 'MNQ(%' OR" + + " nmv.name = 'MQ' OR" + + " nmv.name LIKE 'MQ(%' OR" + + " nmv.name = 'MHQ' OR" + + " nmv.name LIKE 'MHQ(%' OR" + + " nmv.name = 'HQ5' OR" + + " nmv.name LIKE 'HQ5(%') AND" + + " g.river_id = :river_id " + + "ORDER BY" + + " g.id"; + + protected List<GaugeRange> gauges; + protected boolean isKmUp; + + public GaugeFinder(List<GaugeRange> gauges) { + this(gauges, true); + } + + public GaugeFinder( + List<GaugeRange> gauges, + boolean isKmUp + ) { + this.gauges = gauges; + this.isKmUp = isKmUp; + } + + public boolean getIsKmUp() { + return isKmUp; + } + + public void setIsKmUp(boolean isKmUp) { + this.isKmUp = isKmUp; + } + + public GaugeRange find(double km) { + for (GaugeRange gauge: gauges) { + if (gauge.inside(km)) { + return gauge; + } + } + return null; + } + + public GaugeRange find(Range range) { + return find(isKmUp ? range.start : range.end); + } + + public GaugeRange find(int gaugeId) { + for (GaugeRange gauge: gauges) { + if (gauge.gaugeId == gaugeId) { + return gauge; + } + } + return null; + } + + public List<GaugeRange> getGauges() { + return gauges; + } + + public boolean loadDischargeSectors(Session session, int riverId) { + + SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS) + .addScalar("gauge_id", StandardBasicTypes.INTEGER) + .addScalar("name", StandardBasicTypes.STRING) + .addScalar("value", StandardBasicTypes.DOUBLE); + + query.setInteger("river_id", riverId); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("River " + riverId + " has no discharge sectors."); + return false; + } + + GaugeRange gauge = null; + + for (Object [] row: list) { + int gaugeId = (Integer)row[0]; + String label = (String) row[1]; + Double value = (Double) row[2]; + + if (gauge == null || gauge.gaugeId != gaugeId) { + if ((gauge = find(gaugeId)) == null) { + log.warn("Cannot find gauge for id " + gaugeId + "."); + continue; + } + } + + gauge.addMainValue(label, value); + } + + for (GaugeRange g: gauges) { + g.buildClasses(); + } + + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,133 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import de.intevation.flys.model.River; + +import java.util.ArrayList; +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.type.StandardBasicTypes; + +public class GaugeFinderFactory +{ + private static Logger log = Logger.getLogger(GaugeFinderFactory.class); + + public static final String CACHE_NAME = "gauge-finders"; + + public static final String SQL_GAUGES = + "SELECT" + + " g.id AS gauge_id," + + " g.name AS name," + + " r.a AS a," + + " r.b AS b " + + "FROM gauges g" + + " JOIN ranges r ON g.range_id = r.id " + + "WHERE" + + " g.river_id = :river_id " + + "ORDER BY r.a"; + + private static GaugeFinderFactory INSTANCE; + + protected GaugeFinderFactory() { + } + + public static synchronized GaugeFinderFactory getInstance() { + if (INSTANCE == null) { + INSTANCE = new GaugeFinderFactory(); + } + + return INSTANCE; + } + + public GaugeFinder getGaugeFinder(String riverName) { + River river = RiverFactory.getRiver(riverName); + return river != null + ? getGaugeFinder(river.getId(), river.getKmUp()) + : null; + } + + public synchronized GaugeFinder getGaugeFinder( + int riverId, + boolean isKmUp + ) { + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + return getUncached(riverId, isKmUp); + } + + String cacheKey = riverId + "-" + isKmUp; + Element element = cache.get(cacheKey); + + if (element != null) { + return (GaugeFinder)element.getValue(); + } + + GaugeFinder finder = getUncached(riverId, isKmUp); + + if (finder != null) { + cache.put(new Element(cacheKey, finder)); + } + + return finder; + } + + protected GaugeFinder loadGauges( + Session session, + int riverId, + boolean isKmUp + ) { + SQLQuery query = session.createSQLQuery(SQL_GAUGES) + .addScalar("gauge_id", StandardBasicTypes.INTEGER) + .addScalar("name", StandardBasicTypes.STRING) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE); + + query.setInteger("river_id", riverId); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("River " + riverId + " has no gauges."); + return null; + } + + List<GaugeRange> gauges = new ArrayList<GaugeRange>(); + + for (Object [] row: list) { + int gaugeId = (Integer)row[0]; + String name = (String) row[1]; + double start = (Double) row[2]; + double end = (Double) row[3]; + GaugeRange gauge = new GaugeRange(start, end, name, gaugeId); + gauges.add(gauge); + } + + return new GaugeFinder(gauges, isKmUp); + } + + protected GaugeFinder getUncached(int riverId, boolean isKmUp) { + Session session = SessionHolder.HOLDER.get(); + + GaugeFinder finder = loadGauges(session, riverId, isKmUp); + + if (finder == null + || !finder.loadDischargeSectors(session, riverId)) { + return null; + } + + return finder; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,132 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +public class GaugeRange +extends Range +{ + private static Logger log = Logger.getLogger(GaugeRange.class); + + private static final class Sector implements Serializable { + + int sector; + double value; + + Sector(int sector, double value) { + this.sector = sector; + this.value = value; + } + } // class Sector + + protected String name; + + protected int gaugeId; + + protected Map<String, Double> mainValues; + protected List<Sector> sectors; + + public GaugeRange() { + } + + public GaugeRange(double start, double end, int gaugeId) { + this(start, end, null, gaugeId); + } + + public GaugeRange( + double start, + double end, + String name, + int gaugeId + ) { + super(start, end); + this.name = name; + this.gaugeId = gaugeId; + mainValues = new HashMap<String, Double>(); + sectors = new ArrayList<Sector>(3); + } + + public void addMainValue(String label, Double value) { + int idx = label.indexOf('('); + if (idx >= 0) { + label = label.substring(0, idx); + } + mainValues.put(label, value); + } + + protected Double getMainValue(String label) { + Double v = mainValues.get(label); + if (v == null) { + log.warn("Missing main value '" + + label + "' for gauge " + gaugeId); + } + return v; + } + + public void buildClasses() { + Double mnq = getMainValue("MNQ"); + Double mq = getMainValue("MQ"); + Double mhq = getMainValue("MHQ"); + Double hq5 = getMainValue("HQ5"); + + Double [][] pairs = { + { mnq, mq }, + { mq, mhq }, + { hq5, hq5 } }; + + for (int c = 0; c < pairs.length; ++c) { + Double [] pair = pairs[c]; + if (pair[0] != null && pair[1] != null) { + double value = 0.5*(pair[0] + pair[1]); + sectors.add(new Sector(c, value)); + } + } + } + + public double getSectorBorder(int sector) { + for (Sector s: sectors) { + if (s.sector == sector) { + return s.value; + } + } + return Double.NaN; + } + + public int classify(double value) { + for (Sector sector: sectors) { + if (value < sector.value) { + return sector.sector; + } + } + return sectors.size(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String toString() { + StringBuilder sb = new StringBuilder("sectors: ["); + + for (int i = 0, S = sectors.size(); i < S; ++i) { + if (i > 0) sb.append(", "); + Sector s = sectors.get(i); + sb.append(s.sector).append(": ").append(s.value);; + } + + sb.append("] mainvalues: ").append(mainValues); + + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugesFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,70 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.util.ArrayList; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.River; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.Range; + +import org.hibernate.Session; +import org.hibernate.Query; + +public class GaugesFactory +{ + public static List<Gauge> getGauges(River river) { + return getGauges(river.getName()); + } + + + public static Gauge getGauge(String gaugeName) { + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from Gauge where name=:name"); + query.setParameter("name", gaugeName); + + List<Gauge> res = query.list(); + + return res.isEmpty() ? null : res.get(0); + } + + + public static List<Gauge> getGauges(String river) { + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from Gauge where river.name=:name"); + query.setParameter("name", river); + return query.list(); + } + + public static List<Gauge> filterRanges( + List<Gauge> gauges, + List<double []> ranges + ) { + // XXX: Inefficent! + ArrayList<Range> rs = new ArrayList<Range>(); + for (double [] range: ranges) { + double a = range[0]; + double b = range[1]; + rs.add(new Range(Math.min(a, b), Math.max(a, b), null)); + } + return filter(gauges, rs); + } + + public static List<Gauge> filter(List<Gauge> gauges, List<Range> ranges) { + // TODO: Make it an HQL filter! + ArrayList<Gauge> out = new ArrayList<Gauge>(); + for (Gauge gauge: gauges) { + Range range = gauge.getRange(); + for (Range cmp: ranges) { + if (range.intersects(cmp)) { + out.add(gauge); + break; + } + } + } + return out; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,78 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; +import de.intevation.flys.artifacts.HYKArtifact; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.model.FastCrossSectionLine; + +import java.util.List; + +import org.apache.log4j.Logger; + + +/** + * Trival Facet for HYKs + */ +public class HYKFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(HYKFacet.class); + + /** Trivial constructor, set (maybe localized) description. */ + public HYKFacet(int idx, String description) { + super(idx, HYK, description, ComputeType.FEED, null, null); + } + + + /** + * Set km from cross section- master to HYKArtifact, then fire up + * computation. + * + * @param art artifact to get data from. + * @param context ignored + */ + @Override + public Object getData(Artifact art, CallContext context) { + logger.debug("HYKFacet.getData"); + + String dataKey = CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA; + + List<DataProvider> providers = context.getDataProvider(dataKey); + if (providers.size() < 1) { + logger.warn("Could not find Cross-Section data provider to get master cs km."); + return null; + } + + FastCrossSectionLine crossSection = (FastCrossSectionLine) providers.get(0) + .provideData(dataKey, null, context); + + if(crossSection == null) { + logger.debug("getData: crossSection is null"); + return null; + } + + double km = crossSection.getKm(); + logger.debug("HYKFacet.getData: Master Cross Section is at km: " + km); + + // Set this km at hyk artifact to be evaluated. + HYKArtifact hyk = (HYKArtifact) art; + hyk.setKm(km); + + return hyk.compute(context, hash, stateId, type, false); + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + HYKFacet copy = new HYKFacet(this.index, this.description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,211 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.cache.CacheFactory; +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.HYK; +import de.intevation.flys.model.HYKFlowZone; +import de.intevation.flys.model.HYKFormation; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; +import org.hibernate.Query; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; + + +/** + * Factory to access HYKs (hydrographic values). + */ +public class HYKFactory +{ + private static Logger logger = Logger.getLogger(HYKFactory.class); + + public static String HYK_CACHE_NAME = "hykache"; + + + /** Do not instantiate a HYKFactory. */ + private HYKFactory() { + } + + + /** + * Get List of Zones for given river and km. + */ + public static Object getHYKs(int hykid, double km) { + logger.debug("HYKFactory.getHYKs"); + + Cache cache = CacheFactory.getCache(HYK_CACHE_NAME); + + String cacheKey; + + if (cache != null) { + cacheKey = "" + hykid + "_" + km; + Element element = cache.get(cacheKey); + if (element != null) { + logger.debug("Got hyk from cache"); + return element.getValue(); + } + } + else { + cacheKey = null; + } + + List<Zone> zones = getZonesUncached(hykid, km); + + if (zones != null && cacheKey != null) { + logger.debug("Store hykzones in cache."); + Element element = new Element(cacheKey, zones); + cache.put(element); + } + + return zones; + } + + + /** Return name for hyk with given id. */ + public static String getHykName(int hykid) { + logger.debug("HYKFactory.getHykName " + hykid); + + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "select description from HYK where id = :hykid "); + query.setParameter("hykid", hykid); + + return (String) query.uniqueResult(); + } + + + /** + * Ask DB for hyk zones. + * @param hykid ID of the 'main' HYK to query. + * @param km for which to get the hyk-zones. + * @return according zones. + */ + public static List<Zone> getZonesUncached(int hykid, double km) { + if (logger.isDebugEnabled()) { + logger.debug("HYKFactory.getZoneUncached " + hykid + " km " + km); + } + + Session session = SessionHolder.HOLDER.get(); + + // Find out flow-direction of river. + // OPTIMIZE: 1) query kmUp directly 2) merge queries. + Query rQuery = session.createQuery("from HYK where id = :hykid"); + rQuery.setParameter("hykid", hykid); + rQuery.setMaxResults(1); + HYK hyk = (HYK) rQuery.uniqueResult(); + + double flowDir = hyk.getRiver().getKmUp() ? 1 : -1; + + List<HYKFormation> forms = getHYKFormations(hykid, km, flowDir); + List<Zone> zones = new ArrayList<Zone>(); + + // Take the first one. + if (forms.size() >= 1) { + HYKFormation form = forms.get(0); + // Create respective zones. + for (HYKFlowZone flowZone: form.getZones()) { + Zone z = new Zone(flowZone.getA().doubleValue(), + flowZone.getB().doubleValue(), + flowZone.getType().getName()); + zones.add(z); + } + } + + return zones; + } + + + protected static List<HYKFormation> getHYKFormations( + int hykid, + double km, + double flowDir + ) { + Session session = SessionHolder.HOLDER.get(); + + String SQL = "SELECT " + + " f.id AS FID, " + + " f.distance_vl AS DIST, " + + " e.hyk_id AS HID, " + + " e.km AS KM " + + " FROM hyk_formations f INNER JOIN hyk_entries e " + + " ON e.id = f.hyk_entry_id " + + " WHERE e.hyk_id = :hykid " + + " AND :km between " + + " LEAST(e.km, e.km + :flowDir*(f.distance_vl/1000.0+0.001)) " + + " AND " + + " GREATEST(e.km, e.km + :flowDir*(f.distance_vl/1000.0+0.001))"; + + SQLQuery sqlQuery = session.createSQLQuery(SQL) + .addScalar("FID", StandardBasicTypes.INTEGER) + .addScalar("DIST", StandardBasicTypes.DOUBLE) + .addScalar("HID", StandardBasicTypes.INTEGER) + .addScalar("KM", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("hykid", hykid); + sqlQuery.setDouble("flowDir", flowDir); + sqlQuery.setDouble("km", km); + + logger.debug("HYK SQL: " + sqlQuery.getQueryString()); + + List<Object[]> results = sqlQuery.list(); + + logger.debug("Found " + results.size() + " HYKFormation IDs in DB."); + + if (results == null || results.isEmpty()) { + logger.debug("No HYK found for ID " + hykid + " at km " + km); + return new ArrayList<HYKFormation>(); + } + + Object[] resultSet = results.get(0); + Integer hykFormationId = (Integer) resultSet[0]; + + Query query = session.createQuery("from HYKFormation where id = :id"); + query.setParameter("id", hykFormationId); + query.setMaxResults(1); + + return query.list(); + } + + + /** Labeled section. */ + public static class Zone implements Serializable { + /** Lower end of segment. */ + protected double from; + /** Upper end of segment. */ + protected double to; + /** The label. */ + protected String name; + + /** Constructor for labelled section. */ + public Zone (double from, double to, String name) { + this.from = from; + this.to = to; + this.name = name; + } + + /** Get upper value. */ + public double getTo() { + return to; + } + + /** Get lower value. */ + public double getFrom() { + return from; + } + + /** Get name (type). */ + public String getName() { + return name; + } + } // public static class Zone +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeDifferenceFacet +extends HistoricalDischargeFacet +{ + private static final Logger logger = + Logger.getLogger(HistoricalDischargeDifferenceFacet.class); + + + public HistoricalDischargeDifferenceFacet( + int index, + String name, + String desc + ) { + super(index, name, desc, ComputeType.ADVANCE, null, null); + } + + + public HistoricalDischargeDifferenceFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + + ) { + super(index, name, description, type, hash, stateID); + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + if (logger.isDebugEnabled()) { + logger.debug("Get data for historical discharge difference curves" + + " at index: " + index + " / stateId: " + stateId); + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, false); + + HistoricalWQTimerange[] wqts = (HistoricalWQTimerange[]) res.getData(); + + return wqts[index]; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeFacet extends DataFacet { + + private static final Logger logger = + Logger.getLogger(HistoricalDischargeFacet.class); + + + public HistoricalDischargeFacet() { + } + + + public HistoricalDischargeFacet(int index, String name, String desc) { + super(index, name, desc, ComputeType.ADVANCE, null, null); + } + + + public HistoricalDischargeFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + + ) { + super(index, name, description, type, hash, stateID); + } + + + @Override + public Facet deepCopy() { + WaterlevelFacet copy = new WaterlevelFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + if (logger.isDebugEnabled()) { + logger.debug("Get data for historical discharge curves at index: " + + index + " / stateId: " + stateId); + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, false); + + WQTimerange[] wqts = (WQTimerange[]) res.getData(); + + return wqts[index]; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalWQTimerange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,49 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + + +/** + * A subclass of WQTimerange that stores besides W, Q and Timerange values + * another double value. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalWQTimerange extends WQTimerange { + + protected TDoubleArrayList diffs; + + + public HistoricalWQTimerange(String name) { + super(name); + + diffs = new TDoubleArrayList(); + } + + + public void add(double w, double q, double diff, Timerange t) { + ws.add(w); + qs.add(q); + ts.add(t); + diffs.add(diff); + } + + + /** + * This method requires a 3dim double array for <i>res</i>! + */ + @Override + public double[] get(int idx, double[] res) { + res[0] = ws.getQuick(idx); + res[1] = qs.getQuick(idx); + res[2] = diffs.getQuick(idx); + + return res; + } + + + public double[] getDiffs() { + return diffs.toNativeArray(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,163 @@ +package de.intevation.flys.artifacts.model; + + +public class LayerInfo { + + protected String name; + protected String type; + protected String directory; + protected String data; + protected String connection; + protected String connectionType; + protected String extent; + protected String srid; + protected String group; + protected String groupTitle; + protected String title; + protected String style; + protected String filter; + protected String labelItem; + + + public LayerInfo() { + } + + + public void setName(String name) { + this.name = name; + } + + + public String getName() { + return name; + } + + + public void setType(String type) { + this.type = type; + } + + + public String getType() { + return type; + } + + + public void setDirectory(String directory) { + this.directory = directory; + } + + + public String getDirectory() { + return directory; + } + + + public void setData(String data) { + this.data = data; + } + + + public String getData() { + return data; + } + + + public void setConnection(String connection) { + this.connection = connection; + } + + + public String getConnection() { + return connection; + } + + + public void setConnectionType(String connectionType) { + this.connectionType = connectionType; + } + + + public String getConnectionType() { + return connectionType; + } + + + public void setGroup(String group) { + this.group = group; + } + + + public String getGroup() { + return group; + } + + + public void setGroupTitle(String groupTitle) { + this.groupTitle = groupTitle; + } + + + public String getGroupTitle() { + return groupTitle; + } + + + public void setTitle(String title) { + this.title = title; + } + + + public String getTitle() { + return title; + } + + + public void setExtent(String extent) { + this.extent = extent; + } + + + public String getExtent() { + return extent; + } + + + public void setSrid(String srid) { + this.srid = srid; + } + + + public String getSrid() { + return srid; + } + + + public void setStyle(String style) { + this.style = style; + } + + + public String getStyle() { + return style; + } + + + public void setFilter(String filter) { + this.filter = filter; + } + + + public String getFilter() { + return filter; + } + + public void setLabelItem(String labelItem) { + this.labelItem = labelItem; + } + + public String getLabelItem() { + return labelItem; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,100 @@ +package de.intevation.flys.artifacts.model; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import de.intevation.flys.model.Annotation; +import de.intevation.flys.model.FastAnnotations; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +public class LocationProvider { + + private static final Logger log = + Logger.getLogger(LocationProvider.class); + + + public static final String CACHE_KEY = "location-provider"; + + public static final String PREFIX = "lp-"; + + + private LocationProvider() { + } + + public static String getLocation(String river, double km) { + + FastAnnotations fas = getAnnotations(river, km); + + FastAnnotations.Annotation an = fas.findByKm(km); + + return an != null ? an.getPosition() : null; + } + + public static FastAnnotations getAnnotations(String river) { + return getAnnotations(river, Double.MAX_VALUE); + } + + protected static FastAnnotations getAnnotations(String river, double km) { + + Cache cache = CacheFactory.getCache(CACHE_KEY); + + if (cache == null) { + return uncachedAnnotations(river, km); + } + + String key = PREFIX + river; + + Element element = cache.get(key); + + if (element != null) { + return (FastAnnotations)element.getValue(); + } + + FastAnnotations fas = uncachedAnnotations(river, Double.MAX_VALUE); + + cache.put(new Element(key, fas)); + + return fas; + } + + protected static FastAnnotations uncachedAnnotations( + String river, + double km + ) { + if (km != Double.MAX_VALUE) { + // XXX Fake it by using a standard Annotation. + + Annotation annotation = + AnnotationsFactory.getAnnotation(river, km); + + if (annotation != null) { + FastAnnotations.Annotation fa = + new FastAnnotations.Annotation( + km, Double.NaN, + annotation.getPosition().getValue(), null, null, + Double.NaN, Double.NaN); + return new FastAnnotations( + new FastAnnotations.Annotation [] { fa }); + } + + return new FastAnnotations(new FastAnnotations.Annotation[0]); + } + + long startTime = System.currentTimeMillis(); + + FastAnnotations fas = new FastAnnotations(river); + + long stopTime = System.currentTimeMillis(); + + if (log.isDebugEnabled()) { + log.debug("Loading locations took " + + (stopTime-startTime)/1000f + " secs."); + } + + return fas; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,154 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; + +import de.intevation.artifactdatabase.state.DefaultFacet; + +import de.intevation.flys.artifacts.MainValuesArtifact; +import de.intevation.flys.artifacts.math.Linear; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StickyAxisAnnotation; + +import de.intevation.flys.exports.DurationCurveGenerator; + + +/** + * Facet to show Main Q Values. + * TODO Join with W implementation. + */ +public class MainValuesQFacet +extends DefaultFacet +implements FacetTypes { + + /** Own logger. */ + private static Logger logger = Logger.getLogger(MainValuesQFacet.class); + + /** Do we want MainValues at Gauge (not interpolated)? */ + protected boolean isAtGauge; + + + /** Trivial Constructor. */ + public MainValuesQFacet(String name, String description, boolean atGauge) { + this.description = description; + this.name = name; + this.index = 0; + this.isAtGauge = atGauge; + } + + + /** + * Set the hit-point in Q where a line drawn from the axis would hit the + * curve in WQDay (if hit). + * Employ linear interpolation. + */ + protected static void setHitPoint(WQDay wqday, StickyAxisAnnotation annotation) { + int idx = 0; + float q = annotation.getPos(); + boolean qIncreases = wqday.getQ(0) < wqday.getQ(wqday.size()-1); + if (qIncreases) { + while (idx < wqday.size() && wqday.getQ(idx) < q) { + idx++; + } + } + else { + idx = wqday.size() -1; + while (idx > 0 && wqday.getQ(idx) > q) { + idx--; + } + } + + double day = 0d; + int mod = (qIncreases) ? -1 : +1; + if (idx != 0 && idx <= wqday.size()-1) { + day = Linear.linear(q, wqday.getQ(idx +mod), wqday.getQ(idx), + wqday.getDay(idx+mod), wqday.getDay(idx)); + annotation.setHitPoint((float)day); + } + else { + logger.debug("StickyAnnotation does not hit wqday curve"); + } + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + MainValuesArtifact mvArtifact = (MainValuesArtifact) artifact; + + List<NamedDouble> qs = mvArtifact.getMainValuesQ(isAtGauge); + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + + WQDay wqdays = null; + List<DataProvider> providers = context. + getDataProvider(DurationCurveFacet.BB_DURATIONCURVE); + if (providers.size() < 1) { + logger.warn("Could not find durationcurve data provider."); + } + else { + wqdays = (WQDay) providers.get(0).provideData( + DurationCurveFacet.BB_DURATIONCURVE, + null, + context); + } + + // Rather specific case, Q-Annotations at a maybe second yaxis. + StickyAxisAnnotation annotation = null; + if (this.name.equals(DURATION_MAINVALUES_Q)) { + for (NamedDouble q: qs) { + annotation = + new StickyAxisAnnotation( + q.getName(), + (float) q.getValue(), + StickyAxisAnnotation.SimpleAxis.Y_AXIS, + DurationCurveGenerator.YAXIS.Q.idx); + xy.add(annotation); + if (wqdays != null) { + setHitPoint(wqdays, annotation); + } + } + } + else { + for (NamedDouble q: qs) { + annotation = + new StickyAxisAnnotation( + q.getName(), + (float) q.getValue(), + StickyAxisAnnotation.SimpleAxis.X_AXIS); + xy.add(annotation); + if (wqdays != null) { + setHitPoint(wqdays, annotation); + } + } + } + + return new FLYSAnnotation(description, xy); + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public MainValuesQFacet deepCopy() { + MainValuesQFacet copy = new MainValuesQFacet(this.name, + description, this.isAtGauge); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,133 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; + +import de.intevation.artifactdatabase.state.DefaultFacet; + +import de.intevation.flys.artifacts.MainValuesArtifact; +import de.intevation.flys.artifacts.math.Linear; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StickyAxisAnnotation; + + +/** + * Facet to show Main W Values. + */ +public class MainValuesWFacet +extends DefaultFacet +implements FacetTypes { + + /** Own logger. */ + private static Logger logger = Logger.getLogger(MainValuesWFacet.class); + + /** Do we want MainValues at Gauge (not interpolated)? */ + protected boolean isAtGauge; + + /** Trivial Constructor. */ + public MainValuesWFacet(String name, String description, boolean atGauge) { + this.description = description; + this.name = name; + this.index = 0; + this.isAtGauge = atGauge; + } + + + /** + * Set the hit-point in W where a line drawn from the axis would hit the + * curve in WQDay (if hit). + * Employ linear interpolation. + */ + protected static void setHitPoint(WQDay wqday, StickyAxisAnnotation annotation) { + int idx = 0; + float w = annotation.getPos(); + boolean wIncreases = wqday.getW(0) < wqday.getW(wqday.size()-1); + if (wIncreases) { + while (idx < wqday.size() && wqday.getW(idx) < w) { + idx++; + } + } + else { + idx = wqday.size() -1; + while (idx > 0 && wqday.getW(idx) > w) { + idx--; + } + } + + double day = 0d; + int mod = (wIncreases) ? -1 : +1; + if (idx != 0 && idx < wqday.size()-1-mod) { + day = Linear.linear(w, wqday.getW(idx +mod), wqday.getW(idx), + wqday.getDay(idx+mod), wqday.getDay(idx)); + annotation.setHitPoint((float)day); + } + else { + logger.debug("StickyAnnotation does not hit wqday curve"); + } + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + MainValuesArtifact mvArtifact = (MainValuesArtifact) artifact; + + List<NamedDouble> ws = mvArtifact.getMainValuesW(isAtGauge); + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + + // Find whether a duration curve is on the blackboard. + WQDay wqdays = null; + List<DataProvider> providers = context. + getDataProvider(DurationCurveFacet.BB_DURATIONCURVE); + if (providers.size() < 1) { + logger.warn("Could not find durationcurve data provider."); + } + else { + wqdays = (WQDay) providers.get(0).provideData( + DurationCurveFacet.BB_DURATIONCURVE, + null, + context); + } + + for (NamedDouble w: ws) { + StickyAxisAnnotation annotation = + new StickyAxisAnnotation( + w.getName(), + (float) w.getValue(), + StickyAxisAnnotation.SimpleAxis.Y_AXIS); + xy.add(annotation); + if (wqdays != null) { + setHitPoint(wqdays, annotation); + } + } + + return new FLYSAnnotation(description, xy); + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public MainValuesWFacet deepCopy() { + MainValuesWFacet copy = new MainValuesWFacet(this.name, + description, this.isAtGauge); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,179 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.ArtifactNamespaceContext; + + +/** + * Use an Element (DOM) to store the information about a facet. + * The intent of this facet type is to represent a facet + * stored in an Collection attribute. Different facets can have different + * attributes that we need to parse, but the only thing ManagedFacets need + * to do, is to adjust the attributes "active" and "position". So, those + * values are set directly on the Element, the other attributes aren't + * touched. + */ +public class ManagedDomFacet extends ManagedFacet { + + protected Element facet; + + private static Logger logger = Logger.getLogger(ManagedDomFacet.class); + + + public ManagedDomFacet(Element facet) { + super(null, -1, null, null, -1, -1, -1); + + this.facet = facet; + } + + + @Override + public int getIndex() { + if (this.index < 0) { + String index = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "index"); + + if (index != null && index.length() > 0) { + this.index = Integer.parseInt(index); + } + } + + return this.index; + } + + + @Override + public String getName() { + if (this.name == null || this.name.length() == 0) { + String name = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "facet"); + + this.name = name; + } + + return this.name; + } + + + @Override + public String getDescription() { + if (this.description == null || this.description.length() == 0) { + String description = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "description"); + + this.description = description; + } + + return this.description; + } + + + @Override + public int getPosition() { + if (this.position < 0) { + String position = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "pos"); + + if (position != null && position.length() > 0) { + this.position = Integer.parseInt(position); + } + } + + return this.position; + } + + + @Override + public void setPosition(int position) { + this.position = position; + + // TODO Evaluate whether other set/getAttributes also need + // to use the NAMESPACE_PREFIX. + facet.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX + ":" + "pos", + String.valueOf(position)); + } + + + @Override + public int getActive() { + if (this.active < 0) { + String active = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "active"); + + if (active != null && active.length() > 0) { + this.active = Integer.parseInt(active); + } + } + + return this.active; + } + + + @Override + public void setActive(int active) { + this.active = active; + + facet.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "art:active", + String.valueOf(active)); + } + + + @Override + public int getVisible() { + if (this.visible < 0) { + String visible = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "visible"); + + if (visible != null && visible.length() > 0) { + this.visible = Integer.parseInt(visible); + } + } + + return this.visible; + } + + + @Override + public void setVisible(int visible) { + this.visible = visible; + + facet.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "visible", + String.valueOf(getVisible())); + } + + + @Override + public String getArtifact() { + if (this.uuid == null || this.uuid.length() == 0) { + String uuid = facet.getAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, "artifact"); + + this.uuid = uuid; + } + + return this.uuid; + } + + + /** + * Import into document. + * @param doc Document to be imported to. + */ + @Override + public Node toXML(Document doc) { + return doc.importNode(facet, true); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,134 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.ArtifactNamespaceContext; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + + +/** + * Facet with user-supplied theme-control-information (pos in list, + * active/disabled etc) attached. + */ +public class ManagedFacet extends DefaultFacet { + + /** The uuid of the owner artifact. */ + protected String uuid; + + /** A property that determines the position of this facet. */ + protected int position; + + /** A property that determines if this facet is active or not. */ + protected int active; + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(ManagedFacet.class); + + /** A property that determines if this facet is visible or not. */ + protected int visible; + + + public ManagedFacet() { + } + + public ManagedFacet( + String name, + int index, + String desc, + String uuid, + int pos, + int active, + int visible) + { + super(index, name, desc); + + this.uuid = uuid; + this.position = pos; + this.active = active; + this.visible = visible; + } + + + /** + * Sets position (will be merged to position in ThemeList). + */ + public void setPosition(int pos) { + this.position = pos; + } + + + public int getPosition() { + return position; + } + + + public void setActive(int active) { + this.active = active; + } + + + public int getActive() { + return active; + } + + + public void setVisible(int visible) { + this.visible = visible; + } + + + public int getVisible() { + return visible; + } + + + /** + * Get uuid of related artifact. + * @return uuid of related artifact. + */ + public String getArtifact() { + return uuid; + } + + + public Node toXML(Document doc) { + ElementCreator ec = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element facet = ec.create("theme"); + ec.addAttr(facet, "artifact", getArtifact(), true); + ec.addAttr(facet, "facet", getName(), true); + ec.addAttr(facet, "pos", String.valueOf(getPosition()), true); + ec.addAttr(facet, "active", String.valueOf(getActive()), true); + ec.addAttr(facet, "index", String.valueOf(getIndex()), true); + ec.addAttr(facet, "description", getDescription(), true); + ec.addAttr(facet, "visible", String.valueOf(getVisible()), true); + + return facet; + } + + public void set(ManagedFacet other) { + uuid = other.uuid; + position = other.position; + active = other.active; + } + + @Override + public Facet deepCopy() { + ManagedFacet copy = new ManagedFacet(); + copy.set((DefaultFacet)this); + copy.set((ManagedFacet)this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.ArtifactNamespaceContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + + +public class ManagedFacetAdapter extends ManagedFacet { + + protected Facet facet; + + public ManagedFacetAdapter() { + } + + + protected Logger logger = Logger.getLogger(ManagedFacetAdapter.class); + + public ManagedFacetAdapter( + Facet facet, + String uuid, + int pos, + int active, + int visible + ) { + super( + facet.getName(), + facet.getIndex(), + facet.getDescription(), + uuid, + pos, + active, + visible); + + this.facet = facet; + } + + + @Override + public Node toXML(Document doc) { + ElementCreator ec = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element e = (Element) facet.toXML(doc); + ec.addAttr(e, "artifact", getArtifact(), true); + ec.addAttr(e, "facet", getName(), true); + ec.addAttr(e, "pos", String.valueOf(getPosition()), true); + ec.addAttr(e, "active", String.valueOf(getActive()), true); + ec.addAttr(e, "visible", String.valueOf(getVisible()), true); + + return e; + } + + @Override + public Facet deepCopy() { + ManagedFacetAdapter copy = new ManagedFacetAdapter(); + copy.set((DefaultFacet)this); + copy.set((ManagedFacet)this); + copy.facet = facet.deepCopy(); + return facet; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.ManualPointsArtifact; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + + +/** + * Facet to access ManualPoints that where added by user. + */ +public class ManualPointsFacet +extends DefaultFacet +{ + /** Logger for this class. */ + private static final Logger logger = Logger.getLogger(ManualPointsFacet.class); + + + /** + * Trivial Constructor. + */ + public ManualPointsFacet() { + } + + + /** + * Trivial Constructor for a ManualPointsFacet. + * + * @param index Database-Index to use. + * @param name Name (~type) of Facet. + * @param description Description of Facet. + */ + public ManualPointsFacet(int index, String name, String description) { + super(index, name, description); + } + + + /** + * Get List of ManualPoints for river from Artifact. + * + * @param artifact (ManualPoints-)Artifact to query for list of ManualPoints. + * @param context Ignored. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + ManualPointsArtifact pointsArtifact = (ManualPointsArtifact) artifact; + return pointsArtifact.getPointsData(this.name); + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + ManualPointsFacet copy = new ManualPointsFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,152 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + + +public class MapserverStyle { + + public static class Clazz { + protected List<ClazzItem> items; + protected String name; + + public Clazz(String name) { + this.name = name; + this.items = new ArrayList<ClazzItem>(); + } + + public void addItem(ClazzItem item) { + if (item != null) { + items.add(item); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CLASS\n"); + sb.append("NAME \"" + name + "\"\n"); + + for (ClazzItem item: items) { + item.toString(sb); + } + + sb.append("END\n"); + + return sb.toString(); + } + } + + public interface ClazzItem { + void toString(StringBuilder sb); + } + + public static class Style implements ClazzItem { + protected String color; + protected String outlinecolor; + protected String symbol; + protected int size; + + public void setColor(String color) { + this.color = color; + } + + public void setOutlineColor(String outlinecolor) { + this.outlinecolor = outlinecolor; + } + + public void setSize(int size) { + this.size = size; + } + + public void setSymbol(String symbol) { + if (symbol != null && symbol.length() > 0) { + this.symbol = symbol; + } + } + + public void toString(StringBuilder sb) { + sb.append("STYLE\n"); + sb.append("WIDTH " + String.valueOf(size) + "\n"); + + if (outlinecolor != null) { + sb.append("OUTLINECOLOR " + outlinecolor + "\n"); + } + + if (color != null) { + sb.append("COLOR " + color + "\n"); + } + + if (symbol != null) { + sb.append("SYMBOL '" + symbol + "'\n"); + } + + sb.append("END\n"); + } + } // end of Style + + public static class Label implements ClazzItem { + protected String color; + protected int size; + + public void setColor(String color) { + this.color = color; + } + + public void setSize(int size) { + this.size = size; + } + + @Override + public void toString(StringBuilder sb) { + sb.append("LABEL\n"); + sb.append("ANGLE auto\n"); + sb.append("SIZE " + String.valueOf(size) + "\n"); + sb.append("COLOR " + color + "\n"); + sb.append("TYPE truetype\n"); + sb.append("FONT DefaultFont\n"); + sb.append("POSITION ur\n"); + sb.append("OFFSET 2 2\n"); + sb.append("END\n"); + } + } + + public static class Expression implements ClazzItem { + protected String value; + + public Expression(String value) { + this.value = value; + } + + @Override + public void toString(StringBuilder sb) { + sb.append("EXPRESSION " + value); + sb.append("\n"); + } + } + + + protected List<Clazz> classes; + + + public MapserverStyle() { + classes = new ArrayList<Clazz>(); + } + + public void addClazz(Clazz clazz) { + if (clazz != null) { + classes.add(clazz); + } + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + for (Clazz clazz: classes) { + sb.append(clazz.toString()); + } + + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,192 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.common.utils.DateUtils; + +import de.intevation.flys.model.BedHeightEpoch; +import de.intevation.flys.model.BedHeightEpochValue; +import de.intevation.flys.model.BedHeightSingle; +import de.intevation.flys.model.BedHeightSingleValue; +import de.intevation.flys.model.TimeInterval; + +import de.intevation.flys.artifacts.access.BedHeightAccess; + + +public class MiddleBedHeightCalculation extends Calculation { + + private static final Logger logger = + Logger.getLogger(MiddleBedHeightCalculation.class); + + + public CalculationResult calculate(BedHeightAccess access) { + logger.info("MiddleBedHeightCalculation.calculate"); + + int[] singleIds = access.getBedHeightSingleIDs(); + int[] epochIds = access.getBedHeightEpochIDs(); + + + if (logger.isDebugEnabled()) { + Artifact artifact = access.getArtifact(); + + logger.debug("Artifact '" + artifact.identifier() + "' contains:"); + if (singleIds != null) { + logger.debug(" " + singleIds.length + " single bedheight ids"); + } + + if (epochIds != null) { + logger.debug(" " + epochIds.length + " epoch bedheight ids"); + } + } + + List<BedHeightSingle> singles = getSingles(access, singleIds); + List<BedHeightEpoch> epochs = getEpochs(access, epochIds); + + return buildCalculationResult(access, singles, epochs); + } + + + protected List<BedHeightSingle> getSingles( + BedHeightAccess access, + int[] ids + ) { + List<BedHeightSingle> singles = new ArrayList<BedHeightSingle>(); + + for (int id: ids) { + BedHeightSingle s = BedHeightSingle.getBedHeightSingleById(id); + + if (s != null) { + singles.add(s); + } + else { + logger.warn("Cannot find Sngle by id: " + id); + // TODO ADD WARNING + } + } + + return singles; + } + + + protected List<BedHeightEpoch> getEpochs( + BedHeightAccess access, + int[] ids + ) { + List<BedHeightEpoch> epochs = new ArrayList<BedHeightEpoch>(); + + for (int id: ids) { + BedHeightEpoch e = BedHeightEpoch.getBedHeightEpochById(id); + + if (e != null) { + epochs.add(e); + } + else { + logger.warn("Cannot find Epoch by id: " + id); + // TODO ADD WARNING + } + } + + return epochs; + } + + + protected CalculationResult buildCalculationResult( + BedHeightAccess access, + List<BedHeightSingle> singles, + List<BedHeightEpoch> epochs + ) { + logger.info("MiddleBedHeightCalculation.buildCalculationResult"); + + double kmLo = access.getLowerKM(); + double kmHi = access.getUpperKM(); + + List<MiddleBedHeightData> data = new ArrayList<MiddleBedHeightData>(); + + for (BedHeightSingle single: singles) { + MiddleBedHeightData d = prepareSingleData(single, kmLo, kmHi); + + if (d != null) { + data.add(d); + } + } + + for (BedHeightEpoch epoch: epochs) { + MiddleBedHeightData d = prepareEpochData(epoch, kmLo, kmHi); + + if (d != null) { + data.add(d); + } + } + + logger.debug("Calculation results in " + data.size() + " data objects."); + + return new CalculationResult((MiddleBedHeightData[]) + data.toArray(new MiddleBedHeightData[data.size()]), this); + } + + + protected MiddleBedHeightData prepareSingleData( + BedHeightSingle single, + double kmLo, + double kmHi + ) { + logger.debug("Prepare data for single: " + single.getDescription()); + + List<BedHeightSingleValue> values = + BedHeightSingleValue.getBedHeightSingleValues(single, kmLo, kmHi); + + MiddleBedHeightData data = new MiddleBedHeightData( + single.getYear(), + single.getYear(), + single.getEvaluationBy(), + single.getDescription()); + + for (BedHeightSingleValue value: values) { + data.addKM(value.getStation().doubleValue()); + data.addMiddleHeight(value.getHeight().doubleValue()); + data.addUncertainty(value.getUncertainty().doubleValue()); + data.addSoundingWidth(value.getSoundingWidth().doubleValue()); + data.addDataGap(value.getDataGap().doubleValue()); + data.addWidth(value.getWidth().doubleValue()); + } + + logger.debug("Single contains " + values.size() + " values"); + + return data; + } + + + protected MiddleBedHeightData prepareEpochData( + BedHeightEpoch epoch, + double kmLo, + double kmHi + ) { + logger.debug("Prepare data for epoch: " + epoch.getDescription()); + + TimeInterval ti = epoch.getTimeInterval(); + + List<BedHeightEpochValue> values = + BedHeightEpochValue.getBedHeightEpochValues(epoch, kmLo, kmHi); + + MiddleBedHeightData data = new MiddleBedHeightData( + DateUtils.getYearFromDate(ti.getStartTime()), + DateUtils.getYearFromDate(ti.getStopTime()), + epoch.getEvaluationBy(), + epoch.getDescription() + ); + + for (BedHeightEpochValue value: values) { + data.addKM(value.getStation().doubleValue()); + data.addMiddleHeight(value.getHeight().doubleValue()); + } + + logger.debug("Epoch contains " + values.size() + " values"); + + return data; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,146 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import gnu.trove.TDoubleArrayList; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.resources.Resources; + + +public class MiddleBedHeightData implements Serializable { + + public static final String I18N_SINGLE_NAME = "facet.bedheight_middle.single"; + public static final String I18N_EPOCH_NAME = "facet.bedheight_middle.epoch"; + + private int startYear; + private int endYear; + private String evaluatedBy; + private String description; + + private TDoubleArrayList km; + private TDoubleArrayList middleHeight; + private TDoubleArrayList uncertainty; + private TDoubleArrayList soundingWidth; + private TDoubleArrayList dataGap; + private TDoubleArrayList width; + + + protected MiddleBedHeightData(int start, int end, String eval, String desc) { + this.startYear = start; + this.endYear = end; + this.evaluatedBy = eval; + this.description = desc; + + this.km = new TDoubleArrayList(); + this.middleHeight = new TDoubleArrayList(); + this.uncertainty = new TDoubleArrayList(); + this.soundingWidth = new TDoubleArrayList(); + this.dataGap = new TDoubleArrayList(); + this.width = new TDoubleArrayList(); + } + + + public int getStartYear() { + return startYear; + } + + public int getEndYear() { + return endYear; + } + + public String getEvaluatedBy() { + return evaluatedBy; + } + + public String getDescription() { + return description; + } + + + public void addKM(double km) { + this.km.add(km); + } + + public double getKM(int idx) { + return km.get(idx); + } + + public void addMiddleHeight(double middleHeight) { + this.middleHeight.add(middleHeight); + } + + public double getMiddleHeight(int idx) { + return middleHeight.get(idx); + } + + public void addUncertainty(double uncertainty) { + this.uncertainty.add(uncertainty); + } + + public double getUncertainty(int idx) { + return uncertainty.get(idx); + } + + public void addSoundingWidth(double soundingWidth) { + this.soundingWidth.add(soundingWidth); + } + + public double getSoundingWidth(int idx) { + return soundingWidth.get(idx); + } + + public void addDataGap(double gap) { + this.dataGap.add(gap); + } + + public double getDataGap(int idx) { + return dataGap.get(idx); + } + + public void addWidth(double width) { + this.width.add(width); + } + + public double getWidth(int idx) { + return width.get(idx); + } + + public int size() { + return km.size(); + } + + + public double[][] getMiddleHeightsPoints() { + double[][] points = new double[2][size()]; + + for (int i = 0, n = size(); i < n; i++) { + points[0][i] = getKM(i); + points[1][i] = getMiddleHeight(i); + } + + return points; + } + + + public String getSoundingName(CallContext context) { + if (getStartYear() == getEndYear()) { + return Resources.getMsg( + context.getMeta(), + I18N_SINGLE_NAME, + I18N_SINGLE_NAME, + new Object[] { getStartYear() } + ); + } + else { + return Resources.getMsg( + context.getMeta(), + I18N_EPOCH_NAME, + I18N_EPOCH_NAME, + new Object[] { getStartYear(), getEndYear() } + ); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +/** + * Facet of a MiddleBedHeight curve. + */ +public class MiddleBedHeightFacet extends DataFacet { + + private static Logger logger = Logger.getLogger(MiddleBedHeightFacet.class); + + + public MiddleBedHeightFacet() { + // required for clone operation deepCopy() + } + + + public MiddleBedHeightFacet( + int idx, + String name, + String description, + ComputeType type, + String stateId, + String hash + ) { + super(idx, name, description, type, hash, stateId); + } + + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for middle bed height at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, false); + + MiddleBedHeightData[] data = (MiddleBedHeightData[]) res.getData(); + + return data[index]; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + MiddleBedHeightFacet copy = new MiddleBedHeightFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Module.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,25 @@ +package de.intevation.flys.artifacts.model; + +/** + * Represents a Module as is is loaded from the config + */ +public class Module { + + private String name; + private boolean selected; + + public Module(String name, boolean selected) { + this.name = name; + this.selected = selected; + } + + public String getName() { + return this.name; + } + + public boolean isSelected() { + return this.selected; + } +} + +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/NamedDouble.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,30 @@ +package de.intevation.flys.artifacts.model; + +/** + * Implementation of a <String,double> pair. + */ +public class NamedDouble +extends NamedObjectImpl +{ + protected double value; + + + /** + * @param name name for the given value. + * @param value value. + */ + public NamedDouble(String name, double value) { + super(name); + this.value = value; + } + + + /** + * Get the value. + * @return the value. + */ + public double getValue() { + return this.value; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/NamedObject.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,19 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + + +/** + * This class represents an object that has a name. The default case would be to + * inherit from this class. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface NamedObject +extends Serializable +{ + void setName(String name); + + String getName(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/NamedObjectImpl.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.model; + +public class NamedObjectImpl +implements NamedObject +{ + /** The name of this object.*/ + protected String name; + + public NamedObjectImpl() { + } + + public NamedObjectImpl(String name) { + this.name = name; + } + + + @Override + public void setName(String name) { + this.name = name; + } + + + @Override + public String getName() { + return name; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Parameters.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,334 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.Linear; + +import gnu.trove.TDoubleArrayList; + +import java.io.Serializable; + +import org.apache.log4j.Logger; + +public class Parameters +implements Serializable +{ + private static Logger log = Logger.getLogger(Parameters.class); + + public interface Visitor { + + void visit(double [] row); + + } // interface Visitor + + public static final double EPSILON = 1e-4; + + protected String [] columnNames; + protected TDoubleArrayList [] columns; + + public Parameters() { + } + + public Parameters(String [] columnNames) { + if (columnNames == null || columnNames.length < 1) { + throw new IllegalArgumentException("columnNames too short."); + } + this.columnNames = columnNames; + columns = new TDoubleArrayList[columnNames.length]; + for (int i = 0; i < columns.length; ++i) { + columns[i] = new TDoubleArrayList(); + } + } + + public int columnIndex(String name) { + for (int i = 0; i < columnNames.length; ++i) { + if (columnNames[i].equals(name)) { + return i; + } + } + if (log.isDebugEnabled()) { + log.debug("columnIndex: " + name + " not found in columnNames"); + } + return -1; + } + + public int newRow() { + + int N = columns[0].size(); + + for (int i = 0; i < columns.length; ++i) { + columns[i].add(Double.NaN); + } + + return N; + } + + public double get(int row, int index) { + return columns[index].getQuick(row); + } + + public double get(int i, String columnName) { + int index = columnIndex(columnName); + return index >= 0 + ? columns[index].getQuick(i) + : Double.NaN; + } + + public void set(int row, int index, double value) { + columns[index].setQuick(row, value); + } + + public void set(int i, String columnName, double value) { + int idx = columnIndex(columnName); + if (idx >= 0) { + columns[idx].setQuick(i, value); + } + } + + public boolean set(int row, int [] indices, double [] values) { + boolean invalid = false; + for (int i = 0; i < indices.length; ++i) { + double v = values[i]; + if (Double.isNaN(v)) { + invalid = true; + } + else { + columns[indices[i]].setQuick(row, v); + } + } + return invalid; + } + + public boolean set(int row, String [] names, double [] values) { + boolean success = true; + for (int i = 0; i < names.length; ++i) { + int idx = columnIndex(names[i]); + if (idx >= 0) { + columns[idx].setQuick(row, values[i]); + } + else { + success = false; + } + } + return success; + } + + public int size() { + return columns[0].size(); + } + + public int getNumberColumns() { + return columnNames.length; + } + + public String [] getColumnNames() { + return columnNames; + } + + public void removeNaNs() { + W.removeNaNs(columns); + } + + public int [] columnIndices(String [] columns) { + int [] indices = new int[columns.length]; + for (int i = 0; i < columns.length; ++i) { + indices[i] = columnIndex(columns[i]); + } + return indices; + } + + public double getValue(int row, String column) { + int idx = columnIndex(column); + return idx >= 0 + ? columns[idx].getQuick(row) + : Double.NaN; + } + + public double [] get(int row, String [] columns) { + return get(row, columns, new double[columns.length]); + } + + public double [] get(int row, String [] columns, double [] values) { + for (int i = 0; i < columns.length; ++i) { + int idx = columnIndex(columns[i]); + values[i] = idx < 0 + ? Double.NaN + : this.columns[idx].getQuick(row); + } + + return values; + } + + public void get(int row, int [] columnIndices, double [] values) { + for (int i = 0; i < columnIndices.length; ++i) { + int index = columnIndices[i]; + values[i] = index >= 0 && index < columns.length + ? columns[index].getQuick(row) + : Double.NaN; + } + } + + public int binarySearch(String columnName, double value) { + return binarySearch(columnIndex(columnName), value); + } + + /** + * Performes a binary search in the column identified by its + * index. + * @return Index of found element or negative insertion point (shifted by one) + */ + public int binarySearch(int columnIndex, double value) { + TDoubleArrayList column = columns[columnIndex]; + return column.binarySearch(value); + } + + public int binarySearch(String columnName, double value, double epsilon) { + return binarySearch(columnIndex(columnName), value, epsilon); + } + + public int binarySearch(int columnIndex, double value, double epsilon) { + if (epsilon < 0d) epsilon = -epsilon; + double vl = value - epsilon; + double vh = value + epsilon; + + TDoubleArrayList column = columns[columnIndex]; + int lo = 0, hi = column.size()-1; + while (hi >= lo) { + int mid = (lo + hi) >> 1; + double v = column.getQuick(mid); + if (v < vl) lo = mid + 1; + else if (v > vh) hi = mid - 1; + else return mid; + } + + return -(lo + 1); + } + + public double [] interpolate(int columnIndex, double key) { + return interpolate(columnIndex, key, new double[columns.length]); + } + + public double [] interpolate(String columnName, double key) { + return interpolate( + columnIndex(columnName), key, new double[columns.length]); + } + + public double [] interpolate( + String columnName, + double key, + double [] values + ) { + return interpolate(columnIndex(columnName), key, values); + } + + public double [] interpolate( + int columnIndex, + double key, + double [] values + ) { + int row = binarySearch(columnIndex, key, EPSILON); + + if (row >= 0) { // direct hit + for (int i = 0; i < values.length; ++i) { + values[i] = columns[i].getQuick(row); + } + } + else { + row = -row - 1; + if (row < 1 || row >= size()) { + return null; + } + double v1 = columns[columnIndex].getQuick(row-1); + double v2 = columns[columnIndex].getQuick(row); + double factor = Linear.factor(key, v1, v2); + for (int i = 0; i < values.length; ++i) { + values[i] = Linear.weight( + factor, + columns[i].getQuick(row-1), + columns[i].getQuick(row)); + } + } + return values; + } + + + public double [] interpolate( + String keyName, + double key, + String [] columnNames + ) { + int keyIndex = columnIndex(keyName); + return keyIndex < 0 + ? null + : interpolate(keyIndex, key, columnNames); + } + + public double [] interpolate( + int keyIndex, + double key, + String [] columnNames + ) { + int row = binarySearch(keyIndex, key, EPSILON); + + if (row >= 0) { // direct match + double [] values = new double[columnNames.length]; + for (int i = 0; i < values.length; ++i) { + int ci = columnIndex(columnNames[i]); + values[i] = ci < 0 + ? Double.NaN + : columns[ci].getQuick(row); + } + return values; + } + + row = -row - 1; + if (row < 1 || row >= size()) { + log.debug("interpolate: row is out of bounds"); + return null; + } + + double v1 = columns[keyIndex].getQuick(row-1); + double v2 = columns[keyIndex].getQuick(row); + double factor = Linear.factor(key, v1, v2); + + double [] values = new double[columnNames.length]; + + for (int i = 0; i < values.length; ++i) { + int ci = columnIndex(columnNames[i]); + values[i] = ci < 0 + ? Double.NaN + : Linear.weight( + factor, + columns[ci].getQuick(row-1), + columns[ci].getQuick(row)); + } + + return values; + } + + public boolean isSorted(String columnName) { + return isSorted(columnIndex(columnName)); + } + + public boolean isSorted(int columnIndex) { + TDoubleArrayList column = columns[columnIndex]; + for (int i = 1, N = column.size(); i < N; ++i) { + if (column.getQuick(i-1) > column.getQuick(i)) { + return false; + } + } + return true; + } + + public void visit(Visitor visitor) { + visit(visitor, new double[columns.length]); + } + + public void visit(Visitor visitor, double [] data) { + for (int i = 0, R = size(); i < R; ++i) { + for (int j = 0; j < data.length; ++j) { + data[j] = columns[j].getQuick(i); + } + visitor.visit(data); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,300 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +public class QRangeTree +implements Serializable +{ + private static Logger log = Logger.getLogger(QRangeTree.class); + + public static final double EPSILON = 1e-4; + + public static class Node + implements Serializable + { + Node left; + Node right; + Node prev; + Node next; + + double a; + double b; + double q; + + public Node() { + } + + public Node(double a, double b, double q) { + this.a = a; + this.b = b; + this.q = q; + } + + protected final double interpolatePrev(double pos) { + /* + f(prev.b) = prev.q + f(a) = q + + prev.q = m*prev.b + n + q = m*a + n <=> n = q - m*a + + q - prev.q = m*(a - prev.b) + + m = (q - prev.q)/(a - prev.b) # a != prev.b + */ + + if (a == prev.b) { + return 0.5*(q + prev.q); + } + double m = (q - prev.q)/(a - prev.b); + double n = q - m*a; + return m*pos + n; + } + + protected final double interpolateNext(double pos) { + /* + f(next.a) = next.q + f(b) = q + + next.q = m*next.a + n + q = m*b + n <=> n = q - m*b + + q - next.q = m*(b - next.a) + m = (q - next.q)/(b - next.a) # b != next.a + */ + + if (b == next.a) { + return 0.5*(q + next.q); + } + double m = (q - next.q)/(b - next.a); + double n = q - m*b; + return m*pos + n; + } + + public double findQ(double pos) { + + Node current = this; + for (;;) { + if (pos < current.a) { + if (current.left != null) { + current = current.left; + continue; + } + return current.prev != null + ? current.interpolatePrev(pos) + : Double.NaN; + } + if (pos > current.b) { + if (current.right != null) { + current = current.right; + continue; + } + return current.next != null + ? current.interpolateNext(pos) + : Double.NaN; + } + return current.q; + } + } + } // class Node + + protected Node root; + + public QRangeTree() { + } + + public static final class AccessQAB { + private int startIndex; + + public AccessQAB(int startIndex) { + this.startIndex = startIndex; + } + + public Double getQ(Object [] row) { + return (Double)row[startIndex]; + } + + public Double getA(Object [] row) { + return (Double)row[startIndex+1]; + } + + public Double getB(Object [] row) { + return (Double)row[startIndex+2]; + } + } + + public static final AccessQAB WITH_COLUMN = new AccessQAB(1); + public static final AccessQAB WITHOUT_COLUMN = new AccessQAB(0); + + /** wstQRanges need to be sorted by range.a */ + public QRangeTree(List<Object []> qRanges, int start, int stop) { + this(qRanges, WITH_COLUMN, start, stop); + } + + public QRangeTree( + List<Object []> qRanges, + AccessQAB accessQAB, + int start, + int stop + ) { + if (stop <= start) { + return; + } + + int N = stop-start; + + List<Node> nodes = new ArrayList<Node>(N); + + Node last = null; + + for (int i = 0; i < N; ++i) { + Object [] qRange = qRanges.get(start + i); + Double q = accessQAB.getQ(qRange); + Double a = accessQAB.getA(qRange); + Double b = accessQAB.getB(qRange); + + double av = a != null ? a.doubleValue() : -Double.MAX_VALUE; + double bv = b != null ? b.doubleValue() : Double.MAX_VALUE; + double qv = q.doubleValue(); + + // If nodes are directly neighbored and Qs are the same + // join them. + if (last != null + && Math.abs(last.b - av) < EPSILON + && Math.abs(last.q - qv) < EPSILON) { + last.b = bv; + } + else { + nodes.add(last = new Node(av, bv, qv)); + } + } + + if (log.isDebugEnabled()) { + log.debug("Before/after nodes join: " + + N + "/" + nodes.size()); + } + + root = wireTree(nodes); + } + + protected static Node wireTree(List<Node> nodes) { + int N = nodes.size(); + for (int i = 0; i < N; ++i) { + Node node = nodes.get(i); + if (i > 0 ) node.prev = nodes.get(i-1); + if (i < N-1) node.next = nodes.get(i+1); + } + + return buildTree(nodes, 0, N-1); + } + + protected static Node buildTree(List<Node> nodes, int lo, int hi) { + + if (lo > hi) { + return null; + } + + int mid = (lo + hi) >> 1; + Node parent = nodes.get(mid); + + parent.left = buildTree(nodes, lo, mid-1); + parent.right = buildTree(nodes, mid+1, hi); + + return parent; + } + + public double findQ(double pos) { + return root != null ? root.findQ(pos) : Double.NaN; + } + + protected Node head() { + Node head = root; + while (head.left != null) { + head = head.left; + } + return head; + } + + public List<Range> findSegments(double a, double b) { + if (a > b) { double t = a; a = b; b = t; } + return findSegments(new Range(a, b)); + } + + public List<Range> findSegments(Range range) { + List<Range> segments = new ArrayList<Range>(); + + // Linear scan should be good enough here. + for (Node curr = head(); curr != null; curr = curr.next) { + if (!range.disjoint(curr.a, curr.b)) { + Range r = new Range(curr.a, curr.b); + if (r.clip(range)) { + segments.add(r); + } + } + } + + return segments; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + inorder(root, sb); + return sb.toString(); + } + + protected static void inorder(Node node, StringBuilder sb) { + if (node != null) { + inorder(node.left, sb); + sb.append('[') + .append(node.a) + .append(", ") + .append(node.b) + .append(": ") + .append(node.q) + .append(']'); + inorder(node.right, sb); + } + } + + private static final String name(Object o) { + return String.valueOf(System.identityHashCode(o) & 0xffffffffL); + } + + public String toGraph() { + StringBuilder sb = new StringBuilder(); + sb.append("subgraph c"); + sb.append(name(this)); + sb.append(" {\n"); + if (root != null) { + java.util.Deque<Node> stack = new java.util.ArrayDeque<Node>(); + stack.push(root); + while (!stack.isEmpty()) { + Node current = stack.pop(); + String name = "n" + name(current); + sb.append(name); + sb.append(" [label=\""); + sb.append(current.a).append(", ").append(current.b); + sb.append(": ").append(current.q).append("\"]\n"); + if (current.left != null) { + String leftName = name(current.left); + sb.append(name).append(" -- n").append(leftName).append("\n"); + stack.push(current.left); + } + if (current.right != null) { + String rightName = name(current.right); + sb.append(name).append(" -- n").append(rightName).append("\n"); + stack.push(current.right); + } + } + } + sb.append("}\n"); + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,66 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.QSectorArtifact; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + + +/** + * Facet to access QSector that where added by user. + */ +public class QSectorFacet +extends DefaultFacet +{ + /** Logger for this class. */ + private static final Logger logger = Logger.getLogger(QSectorFacet.class); + + + /** + * Trivial Constructor. + */ + public QSectorFacet() { + } + + + /** + * Trivial Constructor for a QSectorFacet. + * + * @param index Database-Index to use. + * @param name Name (~type) of Facet. + * @param description Description of Facet. + */ + public QSectorFacet(int index, String name, String description) { + super(index, name, description); + } + + + /** + * Get List of QSector for river from Artifact. + * + * @param artifact (QSector-)Artifact to query for list of QSector. + * @param context Ignored. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + QSectorArtifact qsectorArtifact = (QSectorArtifact) artifact; + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + return qsectorArtifact.getQSectors(currentKm, context); + } + + + /** Do a deep copy. */ + @Override + public Facet deepCopy() { + QSectorFacet copy = new QSectorFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QW.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,35 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +public class QW +implements Serializable +{ + protected double q; + protected double w; + + public QW() { + } + + public QW(double q, double w) { + this.q = q; + this.w = w; + } + + public double getQ() { + return q; + } + + public void setQ(double q) { + this.q = q; + } + + public double getW() { + return w; + } + + public void setW(double w) { + this.w = w; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QWDDateRange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,24 @@ +package de.intevation.flys.artifacts.model; + + +import java.io.Serializable; + +import de.intevation.flys.artifacts.model.fixings.QWD; + +public class QWDDateRange +implements Serializable +{ + + public QWD qwd; + public DateRange dateRange; + + public QWDDateRange(QWD qwd, DateRange dr) { + this.qwd = qwd; + this.dateRange = dr; + } + + public QWD getQWD() { + return qwd; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Range.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,63 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +public class Range implements Serializable { + + public static final double EPSILON = 1e-5; + + protected double start; + protected double end; + + public Range() { + } + + public Range(Range other) { + start = other.start; + end = other.end; + } + + public Range(double start, double end) { + this.start = start; + this.end = end; + } + + public double getStart() { + return start; + } + + public double getEnd() { + return end; + } + + public boolean disjoint(double ostart, double oend) { + return start > oend || ostart > end; + } + + public boolean disjoint(Range other) { + return start > other.end || other.start > end; + } + + public boolean intersects(Range other) { + return !disjoint(other); + } + + public void extend(Range other) { + if (other.start < start) start = other.start; + if (other.end > end ) end = other.end; + } + + public boolean clip(Range other) { + if (disjoint(other)) return false; + + if (other.start > start) start = other.start; + if (other.end < end ) end = other.end; + + return true; + } + + public boolean inside(double x) { + return x > start-EPSILON && x < end+EPSILON; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,32 @@ +package de.intevation.flys.artifacts.model; + +import java.util.Arrays; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class RangeWithValues extends Range { + + protected double[] values; + + public RangeWithValues() { + } + + public RangeWithValues(double lower, double upper, double[] values) { + super(lower, upper); + this.values = values; + } + + public double[] getValues() { + return values; + } + + @Override + public String toString() { + return new StringBuilder("start=").append(start) + .append(" end=" ).append(end) + .append(" values=[").append(Arrays.toString(values)).append(']') + .toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,150 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + + +/** Facet for W-over-Ws. */ +public class ReferenceCurveFacet +extends DataFacet +{ + private static Logger log = Logger.getLogger(ReferenceCurveFacet.class); + + public static final String CONTEXT_KEY = "reference.curve.axis.scale"; + + /** Blackboard data provider key for reference curves start km. */ + public static final String BB_REFERENCECURVE_STARTKM = + "reference_curve.startkm"; + + /** Blackboard data provider key for reference curves end kms. */ + public static final String BB_REFERENCECURVE_ENDKMS = + "reference_curve.endkms"; + + + public ReferenceCurveFacet() { + } + + + public ReferenceCurveFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + + public ReferenceCurveFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + ) { + super(index, name, description, type, hash, stateID); + } + + + public Object getData(Artifact artifact, CallContext context) { + + if (log.isDebugEnabled()) { + log.debug("Get data for reference curve at index: " + index + + " /stateId: " + stateId); + } + + return getWWQQ(artifact, context); + } + + + /** + * Can provide parameters of reference curve + * @param key will respond on BB_REFERENCECURVE START/ENDKMS + * @param param ignored + * @param context ignored + * @return whatever parameters for reference curve + */ + @Override + public Object provideBlackboardData(Artifact artifact, + Object key, + Object param, + CallContext context + ) { + WINFOArtifact winfo = (WINFOArtifact) artifact; + if (key.equals(BB_REFERENCECURVE_STARTKM)) { + return winfo.getReferenceStartKm(); + } + else if (key.equals(BB_REFERENCECURVE_ENDKMS)) { + return winfo.getReferenceEndKms(); + } + else { + return null; + } + } + + + protected WWQQ getWWQQ(Artifact artifact, CallContext context) { + FLYSArtifact winfo = (FLYSArtifact)artifact; + + CalculationResult res = (CalculationResult) + winfo.compute(context, hash, stateId, type, false); + + return ((WWQQ [])res.getData())[index]; + } + + + @Override + public void set(Facet other) { + super.set(other); + ReferenceCurveFacet o = (ReferenceCurveFacet)other; + type = o.type; + hash = o.hash; + stateId = o.stateId; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + ReferenceCurveFacet copy = new ReferenceCurveFacet(); + copy.set(this); + return copy; + } + + + @Override + public List getStaticDataProviderKeys(Artifact art) { + List list = new ArrayList(); + list.add(BB_REFERENCECURVE_STARTKM); + list.add(BB_REFERENCECURVE_ENDKMS); + return list; + } + + + @Override + public List getDataProviderKeys(Artifact art, CallContext context) { + + // compute / get data + Object obj = context.getContextValue(CONTEXT_KEY); + + if (!(obj instanceof WWAxisTypes)) { + obj = new WWAxisTypes(getWWQQ(art, context)); + context.putContextValue(CONTEXT_KEY, obj); + } + else { + ((WWAxisTypes)obj).classify(getWWQQ(art, context)); + } + + return getStaticDataProviderKeys(art);//Collections.emptyList(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,179 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.awt.geom.Point2D; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; + +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.math.Linear; + +/** + * Facet to access a point. + */ +public class RelativePointFacet +extends BlackboardDataFacet +implements FacetTypes { + + /** Own logger. */ + private static Logger logger = Logger.getLogger(RelativePointFacet.class); + + /** Trivial Constructor. */ + public RelativePointFacet(String description) { + this(RELATIVE_POINT, description); + } + + + public RelativePointFacet(String name, String description) { + this.name = name; + this.description = description; + this.index = 0; + } + + + protected Point2D calculateDurationCurvePoint(CallContext context, + StaticWKmsArtifact artifact) + { + // TODO here and in reference curve calc: Do warn if more than 1 + // provider found or (way better) handle it. + Object wqdays = null; + double km = 0d; + List<DataProvider> providers = context. + getDataProvider(DurationCurveFacet.BB_DURATIONCURVE); + if (providers.size() < 1) { + logger.warn("Could not find durationcurve data provider."); + } + else { + wqdays = providers.get(0).provideData( + DurationCurveFacet.BB_DURATIONCURVE, + null, + context); + } + List<DataProvider> kmproviders = context. + getDataProvider(DurationCurveFacet.BB_DURATIONCURVE_KM); + if (kmproviders.size() < 1) { + logger.warn("Could not find durationcurve.km data provider."); + } + else { + logger.debug("Found durationcurve.km data provider."); + String dckm = providers.get(0).provideData( + DurationCurveFacet.BB_DURATIONCURVE_KM, + null, + context).toString(); + km = Double.valueOf(dckm); + } + + if (wqdays != null) { + // Which W at this km? + double w = artifact.getWAtKmLin(artifact.getWKms(0), km); + if (w == -1) { + logger.warn("w is -1, already bad sign!"); + } + // Where is this W passed by in the wq-curve? + WQDay wqday = (WQDay) wqdays; + // Doing a linear Day Of KM. + int idx = 0; + boolean wIncreases = wqday.getW(0) < wqday.getW(wqday.size()-1); + if (wIncreases) { + while (idx < wqday.size() && wqday.getW(idx) < w) { + idx++; + } + } + else { + idx = wqday.size() -1; + while (idx > 0 && wqday.getW(idx) > w) { + idx--; + } + } + + double day = 0d; + int mod = (wIncreases) ? -1 : +1; + if (idx != 0 && idx <= wqday.size()-1) { + day = Linear.linear(w, wqday.getW(idx+mod), wqday.getW(idx), + wqday.getDay(idx+mod), wqday.getDay(idx)); + } + + return new Point2D.Double((double) day, w); + } + logger.warn("not wqkms / w / day found"); + // TODO better signal failure. + return new Point2D.Double(0d, 0d); + } + + + /** + * Calculate a reference curve point, that is, a point made of + * the Ws from start and end km param of the reference curve. + */ + public Point2D calculateReferenceCurvePoint(CallContext context, + StaticWKmsArtifact artifact) { + List<DataProvider> providers = context. + getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM); + if (providers.size() < 1) { + logger.warn("Could not find reference curve startkm data provider."); + } + + Double start = (Double) providers.get(0). + provideData(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM, null, context); + + providers = context. + getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS); + if (providers.size() < 1) { + logger.warn("Could not find reference curve endkms data provider."); + } + double[] ends = (double[]) providers.get(0). + provideData(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS, null, context); + + logger.debug("Got s " + start + " e " + ends); + double startW = artifact.getWAtKmLin(artifact.getWKms(0), start.doubleValue()); + // TODO handle multiple ends. + double endW = artifact.getWAtKmLin(artifact.getWKms(0), ends[0]); + logger.debug("Gotw s " + startW + " e " + endW); + return new Point2D.Double(startW, endW); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + StaticWKmsArtifact staticData = (StaticWKmsArtifact) artifact; + // Find out whether we live in a duration curve context, there we would + // provide only a single point. + + if (context.getDataProvider( + DurationCurveFacet.BB_DURATIONCURVE_KM).size() > 0) { + return calculateDurationCurvePoint(context, staticData); + } + else if (context.getDataProvider( + ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM).size() > 0) { + return calculateReferenceCurvePoint(context, staticData); + } + + // TODO better signal failure. + return new Point2D.Double(0d, 0d); + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public RelativePointFacet deepCopy() { + RelativePointFacet copy = new RelativePointFacet(description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +import org.apache.log4j.Logger; + +public class ReportFacet +extends DefaultFacet +implements FacetTypes +{ + private static Logger logger = Logger.getLogger(ReportFacet.class); + + protected ComputeType type; + protected String hash; + protected String stateId; + + public ReportFacet() { + this(ComputeType.ADVANCE); + } + + public ReportFacet(ComputeType type) { + super(0, REPORT, "report"); + this.type = type; + } + + + public ReportFacet(ComputeType type, String hash, String stateId) { + super(0, REPORT, "report"); + this.type = type; + this.hash = hash; + this.stateId = stateId; + } + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("get report data"); + + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult cr = (CalculationResult)flys.compute( + context, hash, stateId, type, false); + + return cr.getReport(); + } + + @Override + public Facet deepCopy() { + ReportFacet copy = new ReportFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,71 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.River; + +import org.hibernate.Query; +import org.hibernate.Session; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class RiverFactory { + + /** We don't need to instantiate concrete objects of this class. */ + private RiverFactory() { + } + + + /** + * Returns all rivers that were found in the backend. + * + * @return all rivers. + */ + public static List<River> getRivers() { + Session session = SessionHolder.HOLDER.get(); + + return session.createQuery("from River order by name").list(); + } + + + /** + * Returns a River object fetched from database based on its id. + * + * @param river_id The id of the desired river. + * + * @return the river. + */ + public static River getRiver(int river_id) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery("from River where id=:river_id"); + query.setParameter("river_id", river_id); + + List<River> rivers = query.list(); + + return rivers.isEmpty() ? null : rivers.get(0); + } + + + /** + * Returns a River object fetched from database based on its name. + * + * @param river The name of a river. + * + * @return the River object. + */ + public static River getRiver(String river) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from River where name =:name"); + query.setParameter("name", river); + + List<River> rivers = query.list(); + + return rivers.isEmpty() ? null : rivers.get(0); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/SQOverview.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,209 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.text.SimpleDateFormat; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.type.StandardBasicTypes; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.flys.utils.KMIndex; + +public class SQOverview +implements Serializable +{ + private static Logger log = Logger.getLogger(SQOverview.class); + + /** + * Serial version UId. + */ + private static final long serialVersionUID = -8934372438968398508L; + + public interface Filter { + + boolean accept(KMIndex<List<Date>> entry); + + } // interface Filter + + + public static final Filter ACCEPT = new Filter() { + @Override + public boolean accept(KMIndex<List<Date>> entry) { + return true; + } + }; + + public static class KmFilter implements Filter { + + protected double km; + + public KmFilter (double km) { + this.km = km; + } + @Override + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getKm() == km) { + return true; + } + } + return false; + } + }; + + public static class DateFilter implements Filter { + + protected Date date; + + public DateFilter (Date date) { + this.date = date; + } + @Override + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getValue().equals(this.date)) { + return true; + } + } + return false; + } + }; + + public static final double EPSILON = 1e-4; + + public static final String DATE_FORMAT = "dd.MM.yyyy"; + + public static final String SQL_SQ = + "SELECT" + + " s.km AS km," + + " m.datum AS datum " + + "FROM messung m " + + " JOIN station s" + + " ON m.stationid = s.stationid " + + " JOIN gewaesser g " + + " ON s.gewaesserid = g.gewaesserid " + + "WHERE" + + " m.q_bpegel IS NOT NULL AND" + + " g.name = :name " + + "ORDER by" + + " s.km, m.datum"; + + protected String riverName; + + protected KMIndex<List<Date>> entries; + + public SQOverview() { + entries = new KMIndex<List<Date>>(); + } + + public SQOverview(String riverName) { + this(); + this.riverName = riverName; + } + + private static final boolean epsilonEquals(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + + protected void loadData(Session session) { + SQLQuery query = session.createSQLQuery(SQL_SQ) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("datum", StandardBasicTypes.DATE); + + query.setString("name", riverName); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("No river '" + riverName + "' found."); + } + + Double prevKm = -Double.MAX_VALUE; + List<Date> dates = new ArrayList<Date>(); + + for (Object [] row: list) { + Double km = (Double)row[0]; + if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) { + entries.add(prevKm, dates); + dates = new ArrayList<Date>(); + } + dates.add((Date)row[1]); + prevKm = km; + } + + if (!dates.isEmpty()) { + entries.add(prevKm, dates); + } + } + + public boolean load(Session session) { + + loadData(session); + + return true; + } + + + public void generateOverview(Document document) { + generateOverview(document, ACCEPT); + } + + public KMIndex<List<Date>> filter(Filter f) { + // TODO: Apply filter + return entries; + } + + public void generateOverview( + Document document, + Filter filter + ) { + KMIndex<List<Date>> filtered = filter(ACCEPT); + + Element sqElement = document.createElement("sq"); + + Element riverElement = document.createElement("river"); + + riverElement.setAttribute("name", riverName); + + sqElement.appendChild(riverElement); + + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + + Element kmE = document.createElement("km"); + + for (KMIndex.Entry<List<Date>> e: filtered) { + + List<Date> dates = e.getValue(); + + if (!dates.isEmpty()) { + Element dEs = document.createElement("dates"); + + for (Date d: dates) { + Element dE = document.createElement("date"); + + dE.setAttribute("value", df.format(d)); + + dEs.appendChild(dE); + } + + kmE.appendChild(dEs); + } + } + + sqElement.appendChild(kmE); + + document.appendChild(sqElement); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SedDBSessionHolder; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import org.hibernate.Session; + +public class SQOverviewFactory { + + private static Logger log = Logger.getLogger(SQOverviewFactory.class); + + public static final String CACHE_NAME = "sq-overviews"; + + private SQOverviewFactory() { + } + + + public static SQOverview getOverview(String river) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Looking for sq overview for river '" + river + "'"); + } + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + if (debug) { + log.debug("Cache not configured."); + } + return getUncached(river); + } + + String key = "sq-over-" + river; + + Element element = cache.get(key); + + if (element != null) { + if (debug) { + log.debug("Overview found in cache"); + } + return (SQOverview)element.getValue(); + } + + SQOverview overview = getUncached(river); + + if (overview != null) { + if (debug) { + log.debug("Store overview in cache."); + } + cache.put(new Element(key, overview)); + } + + return overview; + } + + public static SQOverview getUncached(String river) { + SQOverview overview = new SQOverview(river); + + Session session = SedDBSessionHolder.HOLDER.get(); + + return overview.load(session) ? overview : null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Segment.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,210 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.DoubleUtil; + +import java.io.Serializable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.apache.log4j.Logger; + +public class Segment +implements Serializable +{ + private static Logger log = Logger.getLogger(Segment.class); + + public static final Comparator<Segment> REF_CMP = + new Comparator<Segment>() { + @Override + public int compare(Segment a, Segment b) { + double d = a.referencePoint - b.referencePoint; + if (d < 0d) return -1; + return d > 0d ? +1 : 0; + } + }; + + protected double from; + protected double to; + protected double [] values; + protected double [] backup; + protected double referencePoint; + + public Segment() { + } + + public Segment(double referencePoint) { + this.referencePoint = referencePoint; + } + + public Segment(double from, double to, double [] values) { + this.from = from; + this.to = to; + this.values = values; + } + + public boolean isUp() { + return from < to; + } + + public boolean inside(double km) { + return from < to + ? km >= from && km <= to + : km >= to && km <= from; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Segment: ["); + sb.append("from: ").append(from).append("; to: ") + .append(to) + .append("; ref: ").append(referencePoint) + .append("; values: ("); + for (int i = 0; i < values.length; ++i) { + if (i > 0) sb.append(", "); + sb.append(values[i]); + } + sb.append(")]"); + return sb.toString(); + } + + public void setFrom(double from) { + this.from = from; + } + + public void backup() { + backup = values != null + ? (double [])values.clone() + : null; + } + + public double [] getBackup() { + return backup; + } + + public double getFrom() { + return from; + } + + public void setTo(double to) { + this.to = to; + } + + public double getTo() { + return to; + } + + public void setValues(double [] values) { + this.values = values; + } + + public double [] getValues() { + return values; + } + + public int numValues() { + return values.length; + } + + public void setReferencePoint(double referencePoint) { + this.referencePoint = referencePoint; + } + + public double getReferencePoint() { + return referencePoint; + } + + public static List<Segment> parseSegments(String input) { + + final List<Segment> segments = new ArrayList<Segment>(); + + DoubleUtil.parseSegments(input, new DoubleUtil.SegmentCallback() { + @Override + public void newSegment(double from, double to, double [] values) { + segments.add(new Segment(from, to, values)); + } + }); + + return segments; + } + + public static boolean setReferencePointConvertQ( + List<Segment> segments, + River river, + boolean isQ, + Calculation report + ) { + int numResults = -1; + + boolean success = true; + + // assign reference points + for (Segment segment: segments) { + Gauge gauge = river.maxOverlap(segment.getFrom(), segment.getTo()); + + if (gauge == null) { + log.warn("no gauge found. Defaults to mid point."); + segment.setReferencePoint( + 0.5*(segment.getFrom()+segment.getTo())); + } + else { + double ref = gauge.getStation().doubleValue(); + log.debug( + "reference gauge: " + gauge.getName() + + " (km " + ref + ")"); + segment.setReferencePoint(ref); + } + + double [] values = segment.values; + + if (numResults == -1) { + numResults = values.length; + } + else if (numResults != values.length) { + log.warn("wrong length of values"); + return false; + } + + // convert to Q if needed + if (!isQ && gauge != null) { + + DischargeTable dt = gauge.fetchMasterDischargeTable(); + + double [][] table = + DischargeTables.loadDischargeTableValues(dt, 1); + + // need the original values for naming + segment.backup(); + + for (int i = 0; i < values.length; ++i) { + double w = values[i] / 100.0; + double [] qs = DischargeTables.getQsForW(table, w); + if (qs.length == 0) { + log.warn("No Qs found for W = " + values[i]); + report.addProblem("cannot.find.w.for.q", values[i]); + values[i] = Double.NaN; + success = false; + } + else { + values[i] = qs[0]; + if (qs.length > 1) { + log.warn( + "More than one Q found for W = " + values[i]); + } + } + } + } + } // for all segments + + Collections.sort(segments, Segment.REF_CMP); + + return success; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticBedHeightCacheKey.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +public class StaticBedHeightCacheKey implements Serializable { + public static final String CACHE_NAME = "bedheight-value-table-static"; + + private int time; + private int height_id; + + public StaticBedHeightCacheKey(int column, int wst_id) { + this.height_id = wst_id; + this.time = column; + } + + public int hashCode() { + return (height_id << 8) | time; + } + + public boolean equals(Object other) { + if (!(other instanceof StaticBedHeightCacheKey)) { + return false; + } + StaticBedHeightCacheKey o = (StaticBedHeightCacheKey) other; + return this.height_id == o.height_id && this.time == o.time; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticWKmsCacheKey.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,33 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +/** + * Caching-Key object for 'static' wst- data. + */ +public final class StaticWKmsCacheKey +implements Serializable +{ + public static final String CACHE_NAME = "wst-value-table-static"; + + private int column; + private int wst_id; + + public StaticWKmsCacheKey(int column, int wst_id) { + this.wst_id = wst_id; + this.column = column; + } + + public int hashCode() { + return (wst_id << 8) | column; + } + + public boolean equals(Object other) { + if (!(other instanceof StaticWKmsCacheKey)) { + return false; + } + StaticWKmsCacheKey o = (StaticWKmsCacheKey) other; + return wst_id == o.wst_id && this.column == o.column; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,33 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +/** + * Caching-Key object for 'static' wst- data. + */ +public final class StaticWQKmsCacheKey +implements Serializable +{ + public static final String CACHE_NAME = "wst-wq-value-table-static"; + + private int column; + private int wst_id; + + public StaticWQKmsCacheKey(int column, int wst_id) { + this.wst_id = wst_id; + this.column = column; + } + + public int hashCode() { + return (wst_id << 8) | column; + } + + public boolean equals(Object other) { + if (!(other instanceof StaticWQKmsCacheKey)) { + return false; + } + StaticWQKmsCacheKey o = (StaticWQKmsCacheKey) other; + return this.wst_id == o.wst_id && this.column == o.column; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Timerange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,41 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.util.Date; + + +/** + * This class represents time ranges specified by start and end time. Start and + * end times are stored as long (number of milliseconds since january 1, 1970). + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class Timerange implements Serializable { + + private long start; + private long end; + + + public Timerange(long start, long end) { + this.start = start; + this.end = end; + } + + + public Timerange(Date start, Date stop) { + this.start = start.getTime(); + this.end = stop != null ? stop.getTime() : System.currentTimeMillis(); + } + + + public long getStart() { + return start; + } + + + public long getEnd() { + return end; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/W.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,149 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.utils.DataUtil; + +import gnu.trove.TDoubleArrayList; + +import org.apache.log4j.Logger; + +public class W +extends NamedObjectImpl +{ + private static Logger log = Logger.getLogger(W.class); + + protected TDoubleArrayList ws; + + public W() { + ws = new TDoubleArrayList(); + } + + public W(String name) { + super(name); + ws = new TDoubleArrayList(); + } + + public W(int capacity) { + this(capacity, ""); + } + + public W(int capacity, String name) { + super(name); + ws = new TDoubleArrayList(capacity); + } + + public void add(double value) { + ws.add(value); + } + + public int size() { + return ws.size(); + } + + public double getW(int idx) { + return ws.getQuick(idx); + } + + public double [] getWs() { + return ws.toNativeArray(); + } + + public double [] get(int idx) { + return get(idx, new double [1]); + } + + public double [] get(int idx, double [] dst) { + dst[0] = ws.getQuick(idx); + return dst; + } + + public double minWs() { + return ws.min(); + } + + public static void removeNaNs(TDoubleArrayList [] arrays) { + + int dest = 0; + + int A = arrays.length; + int N = arrays[0].size(); + + OUTER: for (int i = 0; i < N; ++i) { + for (int j = 0; j < A; ++j) { + TDoubleArrayList a = arrays[j]; + double v = a.getQuick(i); + if (Double.isNaN(v)) { + continue OUTER; + } + a.setQuick(dest, v); + } + ++dest; + } + + if (dest < N) { + for (int i = 0; i < A; ++i) { + arrays[i].remove(dest, N-dest); + } + } + } + + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws }); + } + + public boolean guessWaterIncreasing() { + return guessWaterIncreasing(0.05f); + } + + public boolean guessWaterIncreasing(float factor) { + return DataUtil.guessWaterIncreasing(ws, factor); + } + + public int [] longestIncreasingWRangeIndices() { + return longestIncreasingWRangeIndices(new int[2]); + } + + public int [] longestIncreasingWRangeIndices(int [] bounds) { + + int N = size(); + int start = 0; + int stop = 0; + + double lastW = Double.MAX_VALUE; + + for (int i = 0; i < N; ++i) { + double v = ws.getQuick(i); + if (v <= lastW) { + if (stop-start > bounds[1]-bounds[0]) { + bounds[0] = start; + bounds[1] = stop; + if (log.isDebugEnabled()) { + log.debug("new range: " + + bounds[0] + " - " + bounds[1] + " (" + + ws.getQuick(bounds[0]) + ", " + + ws.getQuick(bounds[1]) + ")"); + + } + } + start = stop = i; + } + else { + stop = i; + } + lastW = v; + } + + if (stop-start > bounds[1]-bounds[0]) { + bounds[0] = start; + bounds[1] = stop; + if (log.isDebugEnabled()) { + log.debug("new range @end: " + + bounds[0] + " - " + bounds[1] + " (" + + ws.getQuick(bounds[0]) + ", " + + ws.getQuick(bounds[1]) + ")"); + } + } + + return bounds; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKms.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,20 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + +public interface WKms +extends NamedObject +{ + int size(); + + double getKm(int index); + + double getW(int index); + + TDoubleArrayList allKms(); + + TDoubleArrayList allWs(); + + public boolean guessWaterIncreasing(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,54 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.StaticWKmsArtifact; + +/** + * Facet to show W|km Values. + */ +public class WKmsFacet +extends BlackboardDataFacet +implements FacetTypes { + + /** Trivial Constructor. */ + public WKmsFacet(String description) { + this(STATIC_WKMS, description); + } + + public WKmsFacet(String name, String description) { + this.name = name; + this.description = description; + this.index = 0; + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + StaticWKmsArtifact staticData = + (StaticWKmsArtifact) artifact; + return staticData.getWKms(0); + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public WKmsFacet deepCopy() { + WKmsFacet copy = new WKmsFacet(description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,157 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import org.hibernate.Session; + +import org.hibernate.SQLQuery; +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + + +/** + * Factory to access ready-made WKms for other (than computed) 'kinds' of + * WST-data. + */ +public class WKmsFactory +{ + /** Private logger to use here. */ + private static Logger log = Logger.getLogger(WKmsFactory.class); + + /** Query to get km and ws for wst_id and column_pos. */ + public static final String SQL_SELECT_WS = + "SELECT km, w FROM wst_w_values " + + "WHERE wst_id = :wst_id AND column_pos = :column_pos"; + + /** Query to get name for wst_id and column_pos. */ + public static final String SQL_SELECT_NAME = + "SELECT name " + + "FROM wst_columns "+ + "WHERE wst_id = :wst_id AND position = :column_pos"; + + /** Query to get name (description) for wst_id. */ + public static final String SQL_SELECT_WST_NAME = + "SELECT description from wsts "+ + "WHERE id = :wst_id"; + + + private WKmsFactory() { + } + + + /** + * Get WKms for given column and wst_id, caring about the cache. + */ + public static WKms getWKms(int column, int wst_id) { + log.debug("WKmsFactory.getWKms"); + Cache cache = CacheFactory.getCache(StaticWKmsCacheKey.CACHE_NAME); + + StaticWKmsCacheKey cacheKey; + + if (cache != null) { + cacheKey = new StaticWKmsCacheKey(wst_id, column); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("Got static wst values from cache"); + return (WKms)element.getValue(); + } + } + else { + cacheKey = null; + } + + WKms values = getWKmsUncached(column, wst_id); + + if (values != null && cacheKey != null) { + log.debug("Store static wst values in cache."); + Element element = new Element(cacheKey, values); + cache.put(element); + } + return values; + } + + /** Get name for a WKms. */ + public static String getWKmsName(int wst_id) { + log.debug("WKmsFactory.getWKmsName wst_id/" + wst_id); + + String name = null; + Session session = SessionHolder.HOLDER.get(); + + SQLQuery nameQuery = session.createSQLQuery(SQL_SELECT_WST_NAME) + .addScalar("description", StandardBasicTypes.STRING); + nameQuery.setInteger("wst_id", wst_id); + + List<String> names = nameQuery.list(); + if (names.size() >= 1) { + name = names.get(0); + } + + return name; + } + + /** Get name for a WKms. */ + public static String getWKmsName(int column, int wst_id) { + log.debug("WKmsFactory.getWKmsName c/" + column + ", wst_id/" + wst_id); + + String name = null; + Session session = SessionHolder.HOLDER.get(); + + SQLQuery nameQuery = session.createSQLQuery(SQL_SELECT_NAME) + .addScalar("name", StandardBasicTypes.STRING); + nameQuery.setInteger("wst_id", wst_id); + nameQuery.setInteger("column_pos", column); + + List<String> names = nameQuery.list(); + if (names.size() >= 1) { + name = names.get(0); + } + + return name; + } + + + /** + * Get WKms from db. + * @param column the position columns value + * @param wst_id database id of the wst + * @return according WKms. + */ + public static WKms getWKmsUncached(int column, int wst_id) { + + if (log.isDebugEnabled()) { + log.debug("WKmsFactory.getWKmsUncached c/" + column + ", wst_id/" + wst_id); + } + + WKmsImpl wkms = new WKmsImpl(getWKmsName(column, wst_id)); + + Session session = SessionHolder.HOLDER.get(); + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WS) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("w", StandardBasicTypes.DOUBLE); + sqlQuery.setInteger("wst_id", wst_id); + sqlQuery.setInteger("column_pos", column); + + List<Object []> results = sqlQuery.list(); + + double kms [] = new double[results.size()]; + double ws [] = new double[results.size()]; + + int lastColumn = Integer.MAX_VALUE; + + for (int i = 0, N = results.size(); i < N; i++) { + Object[] row = results.get(i); + wkms.add((Double) row[0], (Double) row[1]); + } + + return wkms; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,99 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + +import de.intevation.flys.utils.DataUtil; + + +public class WKmsImpl +extends NamedObjectImpl +implements WKms +{ + protected TDoubleArrayList kms; + protected TDoubleArrayList ws; + + public WKmsImpl() { + super(""); + kms = new TDoubleArrayList(); + ws = new TDoubleArrayList(); + } + + + /** + * Create named, empty WKms. + */ + public WKmsImpl(String name) { + super(name); + kms = new TDoubleArrayList(); + ws = new TDoubleArrayList(); + } + + + public WKmsImpl(int capacity) { + super(""); + kms = new TDoubleArrayList(capacity); + ws = new TDoubleArrayList(capacity); + } + + + public WKmsImpl(TDoubleArrayList kms, TDoubleArrayList ws) { + this(kms, ws, ""); + } + + + public WKmsImpl( + TDoubleArrayList kms, + TDoubleArrayList ws, + String name + ) { + super(name); + this.kms = kms; + this.ws = ws; + } + + + /** + * Add a W (in NN+m) for a km (in km). + */ + public void add(double km, double w) { + kms.add(km); + ws .add(w); + } + + + @Override + public double getW(int index) { + return ws.getQuick(index); + } + + + @Override + public double getKm(int index) { + return kms.getQuick(index); + } + + @Override + public boolean guessWaterIncreasing() { + return guessWaterIncreasing(0.05f); + } + + protected boolean guessWaterIncreasing(float factor) { + return DataUtil.guessWaterIncreasing(ws, factor); + } + + @Override + public int size() { + return kms.size(); + } + + @Override + public TDoubleArrayList allKms() { + return kms; + } + + @Override + public TDoubleArrayList allWs() { + return ws; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,115 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRField; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class WKmsJRDataSource implements JRDataSource +{ + /** The logger used in this exporter.*/ + private static Logger logger = Logger.getLogger(WKmsJRDataSource.class); + + /** + * + */ + private ArrayList<String[]> data; + private HashMap<String, String> metaData; + + private int index = -1; + + /** + * + */ + public WKmsJRDataSource() + { + data = new ArrayList<String[]>(); + metaData = new HashMap<String, String>(); + } + + + /** + * + */ + public void addData(String[] data) { + this.data.add(data); + } + + + /** + * + */ + public void addMetaData(String key, String value) { + this.metaData.put(key, value); + } + + + /** + * + */ + public boolean next() throws JRException + { + index++; + + return (index < data.size()); + } + + + /** + * + */ + public Object getFieldValue(JRField field) throws JRException + { + Object value = ""; + String fieldName = field.getName(); + if ("river".equals(fieldName)) { + value = metaData.get("river"); + } + else if ("date".equals(fieldName)) { + value = metaData.get("date"); + } + else if ("range".equals(fieldName)) { + value = metaData.get("range"); + } + else if ("gauge".equals(fieldName)) { + value = metaData.get("gauge"); + } + else if ("calculation".equals(fieldName)) { + value = metaData.get("calculation"); + } + else if ("differences".equals(fieldName)) { + value = metaData.get("differences"); + } + else if ("km".equals(fieldName)) { + value = data.get(index)[0]; + } + else if ("W".equals(fieldName)) { + value = data.get(index)[1]; + } + else if ("Q".equals(fieldName)) { + value = data.get(index)[2]; + } + else if ("description".equals(fieldName)) { + value = data.get(index)[3]; + } + else if ("location".equals(fieldName)) { + value = data.get(index)[4]; + } + else if ("gaugename".equals(fieldName)) { + value = data.get(index)[5]; + } + else if ("day".equals(fieldName)) { + value = data.get(index)[6]; + } + return value; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQ.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,102 @@ +package de.intevation.flys.artifacts.model; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import gnu.trove.TDoubleArrayList; + +import org.apache.log4j.Logger; + +public class WQ +extends W +{ + public static final Pattern NUMBERS_PATTERN = + Pattern.compile("\\D*(\\d++.\\d*)\\D*"); + + private static Logger log = Logger.getLogger(WQ.class); + + protected TDoubleArrayList qs; + + public WQ() { + this(""); + } + + public WQ(String name) { + super(name); + qs = new TDoubleArrayList(); + } + + public WQ(int capacity) { + this(capacity, ""); + } + + + public WQ(int capacity, String name) { + super(capacity, name); + qs = new TDoubleArrayList(capacity); + } + + public WQ(double [] qs, double [] ws) { + this(qs, ws, ""); + } + + public WQ(double [] qs, double [] ws, String name) { + super(name); + this.ws = new TDoubleArrayList(ws); + this.qs = new TDoubleArrayList(qs); + } + + + public Double getRawValue() { + if (name == null || name.length() == 0) { + // this should never happen + return null; + } + + Matcher m = NUMBERS_PATTERN.matcher(name); + + if (m.matches()) { + String raw = m.group(1); + + try { + return Double.valueOf(raw); + } + catch (NumberFormatException nfe) { + // do nothing + } + } + + return null; + } + + public void add(double w, double q) { + ws.add(w); + qs.add(q); + } + + public double getQ(int idx) { + return qs.getQuick(idx); + } + + @Override + public double [] get(int idx) { + return get(idx, new double [2]); + } + + @Override + public double [] get(int idx, double [] dst) { + dst[0] = ws.getQuick(idx); + dst[1] = qs.getQuick(idx); + return dst; + } + + public double [] getQs() { + return qs.toNativeArray(); + } + + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws, qs }); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,93 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + +/** + * This class represents a pool of data triples that consists of 'W', 'Q' and + * 'KM' data with corrected 'W' values computed by a BackJumpCorrector. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQCKms +extends WQKms +{ + protected TDoubleArrayList cws; + + public WQCKms() { + } + + public WQCKms(WQKms other, double [] cws) { + this.ws = other.ws; + this.qs = other.qs; + this.kms = other.kms; + this.cws = new TDoubleArrayList(cws); + } + + + public WQCKms(double[] kms, double[] qs, double[] ws, double[] cws) { + super(kms, qs, ws); + + this.cws = new TDoubleArrayList(cws); + } + + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws, qs, cws, kms }); + } + + /** + * Adds a new row to this data pool with corrected W. + * + * @param w a W. + * @param q a Q. + * @param kms a Kms. + * @param cw The corrected W. + */ + public void add(double w, double q, double kms, double cw) { + super.add(w, q, kms); + cws.add(cw); + } + + @Override + public double[] get(int idx) { + return get(idx, new double[4]); + } + + /** + * This method returns a 4dim array of W, Q,Kms and corrected W. + * + * @param idx The position of the triple. + * @param dst destination array + * + * @return a 4dim array of [W, Q, Kms, CW] in dst. + */ + @Override + public double[] get(int idx, double[] dst) { + dst = super.get(idx, dst); + + if (dst.length < 4) { + return dst; + } + + if (cws != null && cws.size() > idx) { + dst[3] = cws.getQuick(idx); + } + + return dst; + } + + public double getC(int idx) { + return cws.getQuick(idx); + } + + + /** + * Returns the double array of corrected W values. + * + * @return the double array of corrected W values. + */ + public double[] getCWs() { + return cws.toNativeArray(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,77 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TIntArrayList; + +/** + * This class represents a pool of data triples that consists of 'W', 'Q' and + * 'Day' data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQDay +extends WQ +{ + protected TIntArrayList days; + + public WQDay() { + super(""); + days = new TIntArrayList(); + } + + public WQDay(int capacity) { + super(capacity); + days = new TIntArrayList(capacity); + } + + public WQDay(int [] days, double [] ws, double [] qs) { + super(qs, ws, ""); + this.days = new TIntArrayList(days); + } + + + public void add(int day, double w, double q) { + super.add(w, q); + days.add(day); + } + + + public boolean isIncreasing() { + int lo = getDay(0); + int hi = getDay(size()-1); + + return lo < hi; + } + + + public int getDay(int idx) { + return days.getQuick(idx); + } + + @Override + public void removeNaNs() { + + int dest = 0; + int N = ws.size(); + + for (int i = 0; i < N; ++i) { + double wi = ws.getQuick(i); + double qi = qs.getQuick(i); + + if (Double.isNaN(wi) || Double.isNaN(qi)) { + continue; + } + + days.setQuick(dest, days.getQuick(i)); + ws.setQuick(dest, wi); + qs.setQuick(dest, qi); + ++dest; + } + + if (dest < N) { + days.remove(dest, N-dest); + ws .remove(dest, N-dest); + qs .remove(dest, N-dest); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.DefaultFacet; + +import de.intevation.flys.artifacts.WQKmsInterpolArtifact; + +/** + * Facet to show W|Q Values. + */ +public class WQFacet +extends DefaultFacet +implements FacetTypes { + + /** Trivial Constructor. */ + public WQFacet(String description) { + this(STATIC_WQ, description); + } + + + /** + * A Facet with WQ data. + */ + public WQFacet(String name, String description) { + this.name = name; + this.description = description; + this.index = 0; + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + WQKmsInterpolArtifact interpolData = + (WQKmsInterpolArtifact) artifact; + Double currentKm = (Double)context.getContextValue("currentKm"); + return interpolData.getWQAtKm(currentKm); + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public WQKmsFacet deepCopy() { + WQKmsFacet copy = new WQKmsFacet(description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,123 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + +import org.apache.log4j.Logger; + + +/** + * This class represents a pool of data triples that consists of 'W', 'Q' and + * 'KM' data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQKms +extends WQ +implements WKms +{ + private static Logger logger = Logger.getLogger(WQKms.class); + + /** The array that contains the 'KMs' values. */ + protected TDoubleArrayList kms; + + + public WQKms() { + this(""); + } + + + public WQKms(String name) { + super(name); + this.kms = new TDoubleArrayList(); + } + + + public WQKms(int capacity) { + this(capacity, ""); + } + + + public WQKms(int capacity, String name) { + super(capacity, name); + this.kms = new TDoubleArrayList(capacity); + } + + public WQKms(double [] kms, double [] qs, double [] ws) { + this(kms, qs, ws, ""); + } + + + public WQKms(double [] kms, double [] qs, double [] ws, String name) { + super(qs, ws, name); + this.kms = new TDoubleArrayList(kms); + } + + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws, qs, kms }); + } + + /** + * Adds a new row to this data pool. + * + * @param w a W. + * @param q a Q. + * @param km a kms. + */ + public void add(double w, double q, double km) { + super.add(w, q); + kms.add(km); + } + + @Override + public double [] get(int idx) { + return get(idx, new double [3]); + } + + /** + * This method returns a triple of W, Q and Kms in a single 3dim array. + * + * @param idx The position of the triple. + * @param dst destination array + * + * @return a triple of [W, Q, Kms] in dst. + */ + @Override + public double [] get(int idx, double [] dst) { + dst[0] = ws .getQuick(idx); + dst[1] = qs .getQuick(idx); + dst[2] = kms.getQuick(idx); + return dst; + } + + @Override + public double getKm(int idx) { + return kms.getQuick(idx); + } + + @Override + public TDoubleArrayList allKms() { + return kms; + } + + @Override + public TDoubleArrayList allWs() { + return ws; + } + + public double[] getKms() { + return kms.toNativeArray(); + } + + /** + * Returns a string that consist of the first and last kilometer. + * + * @return a string that consist of the first and last kilometer. + */ + public String toString() { + double from = getKm(0); + double to = getKm(size()-1); + return from + " - " + to; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,72 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.StaticWQKmsArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet to show W|Q|km Values. + * We have following 'Types' (from FacetTypes): + * String STATIC_WQKMS = "other.wqkms"; + * String STATIC_WQMS_W = "other.wqkms.w"; + * String STATIC_WQKMS_Q = "other.wqkms.q"; + */ +public class WQKmsFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(WQKmsFacet.class); + + /** Trivial Constructor. */ + public WQKmsFacet(String description) { + this(STATIC_WQKMS, description); + } + + + /** + * @param name Name of this facet (we have at least two flavors (w and q). + */ + public WQKmsFacet(String name, String description) { + super(0, name, description, ComputeType.FEED, null, null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("WQKmsFacet.getData"); + + StaticWQKmsArtifact staticData = + (StaticWQKmsArtifact) artifact; + Object res = staticData.compute(context, hash, stateId, type, false); + + return res; + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public WQKmsFacet deepCopy() { + WQKmsFacet copy = new WQKmsFacet(description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,112 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; + +import org.hibernate.Session; + +import org.hibernate.SQLQuery; +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +/** + * Factory to access ready-made WQKms for other (than computed) 'kinds' of + * WST-data. + */ +public class WQKmsFactory +{ + private static Logger log = Logger.getLogger(WQKmsFactory.class); + + /** Query to get km and wqs for wst_id and column_pos. */ + public static final String SQL_SELECT_WQS = + "SELECT position, w, q FROM wst_value_table " + + "WHERE wst_id = :wst_id AND column_pos = :column_pos"; + + /** Query to get name for wst_id and column_pos. */ + public static final String SQL_SELECT_NAME = + "SELECT name " + + "FROM wst_columns "+ + "WHERE wst_id = :wst_id AND position = :column_pos"; + + + /** Hidden constructor, use static methods instead. */ + private WQKmsFactory() { + } + + + /** + * Get WKms for given column and wst_id, caring about the cache. + */ + public static WQKms getWQKms(int column, int wst_id) { + log.debug("WQKmsFactory.getWQKms"); + Cache cache = CacheFactory.getCache(StaticWQKmsCacheKey.CACHE_NAME); + + StaticWQKmsCacheKey cacheKey; + + if (cache != null) { + cacheKey = new StaticWQKmsCacheKey(wst_id, column); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("Got static wst values from cache"); + return (WQKms)element.getValue(); + } + } + else { + cacheKey = null; + } + + WQKms values = getWQKmsUncached(column, wst_id); + + if (values != null && cacheKey != null) { + log.debug("Store static wst values in cache."); + Element element = new Element(cacheKey, values); + cache.put(element); + } + return values; + } + + + /** + * Get WQKms from db. + * @param column the position columns value + * @param wst_id database id of the wst + * @return respective WQKms. + */ + public static WQKms getWQKmsUncached(int column, int wst_id) { + + if (log.isDebugEnabled()) { + log.debug("WQKmsFactory.getWQKmsUncached, column " + + column + ", wst_id " + wst_id); + } + + WQKms wqkms = new WQKms(WKmsFactory.getWKmsName(column, wst_id)); + + Session session = SessionHolder.HOLDER.get(); + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WQS) + .addScalar("position", StandardBasicTypes.DOUBLE) + .addScalar("w", StandardBasicTypes.DOUBLE) + .addScalar("q", StandardBasicTypes.DOUBLE); + sqlQuery.setInteger("wst_id", wst_id); + sqlQuery.setInteger("column_pos", column); + + List<Object []> results = sqlQuery.list(); + + int lastColumn = Integer.MAX_VALUE; + + for (int i = 0, N = results.size(); i < N; i++) { + Object[] row = results.get(i); + // add(w, q, km) + wqkms.add((Double) row[1], (Double) row[2], (Double) row[0]); + } + + return wqkms; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,100 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRField; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class WQTJRDataSource implements JRDataSource +{ + /** The logger used in this exporter.*/ + private static Logger logger = Logger.getLogger(WQTJRDataSource.class); + + /** + * + */ + private ArrayList<String[]> data; + private HashMap<String, String> metaData; + + private int index = -1; + + /** + * + */ + public WQTJRDataSource() + { + data = new ArrayList<String[]>(); + metaData = new HashMap<String, String>(); + } + + + /** + * + */ + public void addData(String[] data) { + this.data.add(data); + } + + + /** + * + */ + public void addMetaData(String key, String value) { + this.metaData.put(key, value); + } + + + /** + * + */ + public boolean next() throws JRException + { + index++; + + return (index < data.size()); + } + + + /** + * + */ + public Object getFieldValue(JRField field) throws JRException + { + Object value = ""; + String fieldName = field.getName(); + if ("river".equals(fieldName)) { + value = metaData.get("river"); + } + else if ("date".equals(fieldName)) { + value = metaData.get("date"); + } + else if ("calculation".equals(fieldName)) { + value = metaData.get("calculation"); + } + else if ("range".equals(fieldName)) { + value = data.get(index)[0]; + } + else if ("W".equals(fieldName)) { + value = data.get(index)[1]; + } + else if ("Q".equals(fieldName)) { + value = data.get(index)[2]; + } + else if ("delta".equals(fieldName)) { + value = data.get(index)[3]; + } + else if ("gaugename".equals(fieldName)) { + value = data.get(index)[4]; + } + return value; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,42 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.List; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQTimerange extends WQ { + + protected List<Timerange> ts; + + + public WQTimerange() { + super(""); + } + + + public WQTimerange(String name) { + super(name); + ts = new ArrayList<Timerange>(); + } + + + public void add(double w, double q, Timerange t) { + ws.add(w); + qs.add(q); + ts.add(t); + } + + + public Timerange getTimerange(int idx) { + return ts.get(idx); + } + + + public Timerange[] getTimeranges() { + return ts.toArray(new Timerange[ts.size()]); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WW.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,200 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.Function; +import de.intevation.flys.artifacts.math.Identity; + +import gnu.trove.TDoubleArrayList; + +public class WW +extends W +{ + public static class ApplyFunctionIterator + { + protected Function function1; + protected Function function2; + protected int pos; + protected WW ww; + + public ApplyFunctionIterator(WW ww) { + this(ww, Identity.IDENTITY, Identity.IDENTITY); + } + + public ApplyFunctionIterator( + WW ww, + Function function1, + Function function2 + ) { + this.ww = ww; + this.function1 = function1; + this.function2 = function2; + } + + public boolean hasNext() { + return pos < ww.size(); + } + + public int size() { + return ww.size(); + } + + public void reset() { + pos = 0; + } + + public WW getWW() { + return ww; + } + + public void get(int idx, double [] wwPair) { + wwPair[0] = function1.value(ww.getW(idx)); + wwPair[1] = function2.value(ww.getW2(idx)); + } + + public void next(double [] wwPair) { + get(pos++, wwPair); + } + } // class FunctionIterator + + protected TDoubleArrayList ws2; + + protected double startKm; + protected double endKm; + + protected Double startDatum; + protected Double endDatum; + + public WW() { + this(""); + } + + public WW(String name) { + super(name); + } + + public WW(int capacity) { + this(capacity, ""); + } + + public WW(int capacity, String name) { + super(capacity, name); + ws2 = new TDoubleArrayList(capacity); + } + + public WW( + String name, + double startKm, + Double startDatum, + double [] ws, + double endKm, + Double endDatum, + double [] ws2 + ) { + this.name = name; + this.ws = new TDoubleArrayList(ws); + this.ws2 = new TDoubleArrayList(ws2); + this.startKm = startKm; + this.startDatum = startDatum; + this.endKm = endKm; + this.endDatum = endDatum; + } + + public WW(String name, TDoubleArrayList ws, TDoubleArrayList ws2) { + this.name = name; + this.ws = ws; + this.ws2 = ws2; + } + + public void add(double w1, double w2) { + ws .add(w1); + ws2.add(w2); + } + + public double getW1(int idx) { + return ws.getQuick(idx); + } + + public double getW2(int idx) { + return ws2.getQuick(idx); + } + + public double [] getWs2() { + return ws2.toNativeArray(); + } + + @Override + public double [] get(int idx) { + return get(idx, new double[2]); + } + + @Override + public double [] get(int idx, double [] dst) { + dst[0] = ws .getQuick(idx); + dst[1] = ws2.getQuick(idx); + return dst; + } + + public double getStartKm() { + return startKm; + } + + public void setStartKm(double startKm) { + this.startKm = startKm; + } + + public double getEndKm() { + return endKm; + } + + public void setEndKm(double endKm) { + this.endKm = endKm; + } + + public Double getStartDatum() { + return startDatum; + } + + public boolean startAtGauge() { + return startDatum != null; + } + + public boolean endAtGauge() { + return endDatum != null; + } + + public void setStartDatum(Double startDatum) { + this.startDatum = startDatum; + } + + public Double getEndDatum() { + return endDatum; + } + + public void setEndDatum(Double endDatum) { + this.endDatum = endDatum; + } + + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws, ws2 }); + } + + public double minWs2() { + return ws2.min(); + } + + // Note that we can also easily define a Function to do so. + public double getRelHeight1Cm(int idx) { + if (this.startAtGauge()) { + return (ws.getQuick(idx) - getStartDatum())*100d; + } + else return ws.getQuick(idx)*100d; + } + + public double getRelHeight2Cm(int idx) { + if (this.endAtGauge()) { + return (ws2.getQuick(idx) - getEndDatum())*100d; + } + else return ws2.getQuick(idx)*100d; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,84 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.Function; +import de.intevation.flys.artifacts.math.Identity; +import de.intevation.flys.artifacts.math.AddScaleFunction; + +public class WWAxisTypes +{ + protected boolean inCm1; + protected boolean inCm2; + + public WWAxisTypes() { + inCm1 = inCm2 = true; + } + + public WWAxisTypes(WW ww) { + this(); + classify(ww); + } + + public void classify(WW ww) { + if (!ww.startAtGauge()) inCm1 = false; + if (!ww.endAtGauge()) inCm2 = false; + } + + public boolean getInCm(int index) { + switch (index) { + case 0: return inCm1; + case 1: return inCm2; + default: return false; + } + } + + public boolean getInCm1() { + return inCm1; + } + + public void setInCm1(boolean inCm1) { + this.inCm1 = inCm1; + } + + public boolean getInCm2() { + return inCm2; + } + + public void setInCm2(boolean inCm2) { + this.inCm2 = inCm2; + } + + public WW.ApplyFunctionIterator transform(WW ww) { + return transform(ww, false); + } + + private static final double zero(Double d) { + return d == null ? 0 : d; + } + + public WW.ApplyFunctionIterator transform(WW ww, boolean normalized) { + + Function function1; + Function function2; + + if (!normalized) { + function1 = inCm1 + ? new AddScaleFunction(-ww.getStartDatum(), 100d) + : Identity.IDENTITY; + + function2 = inCm2 + ? new AddScaleFunction(-ww.getEndDatum(), 100d) + : Identity.IDENTITY; + } + else { + double minW1 = ww.minWs(); + double minW2 = ww.minWs2(); + double scale1 = inCm1 ? 100d : 1d; + double scale2 = inCm2 ? 100d : 1d; + function1 = new AddScaleFunction(-minW1, scale1); + function2 = new AddScaleFunction(-minW2, scale2); + } + + return new WW.ApplyFunctionIterator(ww, function1, function2); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WWQQ.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.flys.artifacts.math.Identity; + +import gnu.trove.TDoubleArrayList; + +public class WWQQ +extends WW +{ + public static class ApplyFunctionIterator + extends WW.ApplyFunctionIterator + { + public ApplyFunctionIterator(WWQQ ww) { + super(ww, Identity.IDENTITY, Identity.IDENTITY); + } + + @Override + public void get(int idx, double [] wwqqPair) { + WWQQ wwqq = (WWQQ)ww; + wwqqPair[0] = function1.value(wwqq.getW(idx)); + wwqqPair[1] = function2.value(wwqq.getW2(idx)); + wwqqPair[2] = wwqq.getQ1(idx); + wwqqPair[3] = wwqq.getQ2(idx); + } + } // class ApplyFunctionIterator + + protected TDoubleArrayList qs1; + protected TDoubleArrayList qs2; + + public WWQQ() { + this(""); + } + + public WWQQ(String name) { + super(name); + } + + public WWQQ(int capacity) { + this(capacity, ""); + } + + public WWQQ(int capacity, String name) { + super(capacity, name); + } + + public WWQQ( + String name, + double startKm, + Double startDatum, + double [] ws1, + double [] qs1, + double endKm, + Double endDatum, + double [] ws2, + double [] qs2 + ) { + super(name, startKm, startDatum, ws1, endKm, endDatum, ws2); + this.qs1 = new TDoubleArrayList(qs1); + this.qs2 = new TDoubleArrayList(qs2); + } + + public double getQ1(int idx) { + return qs1.getQuick(idx); + } + + public double getQ2(int idx) { + return qs2.getQuick(idx); + } + + public double [] getQs1() { + return qs1.toNativeArray(); + } + + public double [] getQs2() { + return qs2.toNativeArray(); + } + + @Override + public double [] get(int idx) { + return get(idx, new double[4]); + } + + @Override + public double [] get(int idx, double [] dst) { + dst[0] = ws .getQuick(idx); + dst[1] = ws2.getQuick(idx); + dst[2] = qs1.getQuick(idx); + dst[3] = qs2.getQuick(idx); + return dst; + } + + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { ws, ws2, qs1, qs2 }); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,121 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRField; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class WWQQJRDataSource implements JRDataSource +{ + /** The logger used in this exporter.*/ + private static Logger logger = Logger.getLogger(WWQQJRDataSource.class); + + /** + * + */ + private ArrayList<String[]> data; + private HashMap<String, String> metaData; + + private int index = -1; + + /** + * + */ + public WWQQJRDataSource() + { + data = new ArrayList<String[]>(); + metaData = new HashMap<String, String>(); + } + + + /** + * + */ + public void addData(String[] data) { + this.data.add(data); + } + + + /** + * + */ + public void addMetaData(String key, String value) { + this.metaData.put(key, value); + } + + + /** + * + */ + public boolean next() throws JRException + { + index++; + + return (index < data.size()); + } + + + /** + * + */ + public Object getFieldValue(JRField field) throws JRException + { + Object value = ""; + String fieldName = field.getName(); + if ("river".equals(fieldName)) { + value = metaData.get("river"); + } + else if ("date".equals(fieldName)) { + value = metaData.get("date"); + } + else if ("calculation".equals(fieldName)) { + value = metaData.get("calculation"); + } + else if ("reference".equals(fieldName)) { + value = metaData.get("reference"); + } + else if ("location".equals(fieldName)) { + value = metaData.get("location"); + } + else if ("km1".equals(fieldName)) { + value = data.get(index)[0]; + } + else if ("location1".equals(fieldName)) { + value = data.get(index)[1]; + } + else if ("W1".equals(fieldName)) { + value = data.get(index)[2]; + } + else if ("Q1".equals(fieldName)) { + value = data.get(index)[3]; + } + else if ("km2".equals(fieldName)) { + value = data.get(index)[4]; + } + else if ("location2".equals(fieldName)) { + value = data.get(index)[5]; + } + else if ("W2".equals(fieldName)) { + value = data.get(index)[6]; + } + else if ("Q2".equals(fieldName)) { + value = data.get(index)[7]; + } + else if ("Wcm1".equals(fieldName)) { + value = data.get(index)[8]; + } + else if ("Wcm2".equals(fieldName)) { + value = data.get(index)[9]; + } + return value; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,125 @@ +package de.intevation.flys.artifacts.model; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.artifacts.math.Linear; + +import org.apache.log4j.Logger; + +/** + * Facet of a Waterlevel (WQKms). + */ +public class WaterlevelFacet extends DataFacet { + + private static Logger logger = Logger.getLogger(WaterlevelFacet.class); + + public WaterlevelFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + public WaterlevelFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + ) { + super(index, name, description, type, hash, stateID); + } + + public WaterlevelFacet() { + } + + protected WQKms [] getWQKms(CalculationResult res) { + return (WQKms [])res.getData(); + } + + /** + * Get waterlevel data. + * @return a WQKms at given index. + */ + public Object getData(Artifact artifact, CallContext context) { + + if (logger.isDebugEnabled()) { + logger.debug("Get data for waterlevels at index: " + index + + " /stateId: " + stateId); + } + + FLYSArtifact winfo = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) + winfo.compute(context, hash, stateId, type, false); + + if (res == null) { + logger.error("WaterlevelFacet.getData: null result"); + return null; + } + + if (winfo == null) { + logger.error("WaterlevelFacet.getData: artifact is null"); + return null; + } + + WQKms [] wqkms = getWQKms(res); + Object KM = context.getContextValue("currentKm"); + if (KM != null) { + logger.debug("interpolate at given km"); + // TODO handle exact match. + + WQKms wqkmsI = wqkms[index]; + double km = (Double)KM; + + // TODO employ DataUtils interface to TDoubleArraList + int size = wqkmsI.size(); + boolean kmIncreasing = wqkmsI.getKm(0) < wqkmsI.getKm(size-1); + int mod = kmIncreasing ? +1 : -1; + int idx = 0; + if (!kmIncreasing) { + while (idx < size && wqkmsI.getKm(idx) < km) { + idx++; + } + } + else { + idx = size-1; + while (idx > 0 && wqkmsI.getKm(idx) > km) { + idx--; + } + } + WQKms resultWQKms = new WQKms(); + if (idx != -1 && idx < size) { + double inW = Linear.linear( + km, + wqkmsI.getKm(idx), wqkmsI.getKm(idx-mod), + wqkmsI.getW(idx), wqkmsI.getW(idx-mod)); + double inQ = Linear.linear( + km, + wqkmsI.getKm(idx), wqkmsI.getKm(idx-mod), + wqkmsI.getQ(idx), wqkmsI.getQ(idx-mod)); + resultWQKms.add(inW, inQ, km); + } + return resultWQKms; + } + + return wqkms != null ? wqkms[index] : null; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + WaterlevelFacet copy = new WaterlevelFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,48 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.River; +import de.intevation.flys.model.Wst; + +import org.hibernate.Query; +import org.hibernate.Session; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WstFactory { + + public static final int DEFAULT_KIND = 0; + + /** We don't need to instantiate concrete objects of this class. */ + private WstFactory() { + } + + + /** + * Returns the Wst object for a given river. + * + * @param river The river. + * + * @return the Wst of <i>river</i>. + */ + public static Wst getWst(River river) { + return getWst(river, DEFAULT_KIND); + } + + public static Wst getWst(River river, int kind) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from Wst where river=:river and kind = :kind"); + query.setParameter("river", river); + query.setInteger("kind", kind); + + List<Wst> wsts = query.list(); + + return wsts.isEmpty() ? null : wsts.get(0); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstLine.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,88 @@ +package de.intevation.flys.artifacts.model; + +import gnu.trove.TDoubleArrayList; + + +/** + * A model class that is used to store a line of a WST. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WstLine { + + /** The kilometer value of the line.*/ + protected double km; + + /** The W values.*/ + protected TDoubleArrayList ws; + + /** The Q values.*/ + protected TDoubleArrayList qs; + + + /** + * A constructor that builds a new WstLine for a specific kilometer. + * + * @param km The kilometer. + */ + public WstLine(double km) { + this.km = km; + this.ws = new TDoubleArrayList(); + this.qs = new TDoubleArrayList(); + } + + + /** + * Adds a pair of W/Q to this line. + * + * @param w The W value. + * @param q The Q value. + */ + public void add(double w, double q) { + ws.add(w); + qs.add(q); + } + + + /** + * Returns the kilometer of this line. + * + * @return the kilomter of this line. + */ + public double getKm() { + return km; + } + + + /** + * Returns the W value at index <i>idx</i> of this line. + * + * @param idx The position of the desired W value. + * + * @return the W at position <i>idx</i>. + */ + public double getW(int idx) { + return ws.size() > idx ? ws.get(idx) : -1d; + } + + + /** + * Returns the Q values of this line. + * + * @return the Q values of this line. + */ + public double[] getQs() { + return qs.toNativeArray(); + } + + + /** + * Returns the number of columns this line consists of. + * + * @return the columns this line consists of. + */ + public int getSize() { + return qs.size(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1262 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import de.intevation.flys.artifacts.math.Linear; +import de.intevation.flys.artifacts.math.Function; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +import org.apache.log4j.Logger; + +import org.apache.commons.math.analysis.interpolation.SplineInterpolator; + +import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; + +import org.apache.commons.math.ArgumentOutsideDomainException; + +import org.apache.commons.math.exception.MathIllegalArgumentException; + +import gnu.trove.TDoubleArrayList; + +/** + * W, Q and km data from database 'wsts' spiced with interpolation algorithms. + */ +public class WstValueTable +implements Serializable +{ + private static Logger log = Logger.getLogger(WstValueTable.class); + + public static final int DEFAULT_Q_STEPS = 500; + + public static final int RELATE_WS_SAMPLES = 200; + + /** + * A Column in the table, typically representing one measurement session. + */ + public static final class Column + implements Serializable + { + protected String name; + + protected QRangeTree qRangeTree; + + public Column() { + } + + public Column(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public QRangeTree getQRangeTree() { + return qRangeTree; + } + + public void setQRangeTree(QRangeTree qRangeTree) { + this.qRangeTree = qRangeTree; + } + } // class Column + + /** + * A (weighted) position used for interpolation. + */ + public static final class QPosition { + + protected int index; + protected double weight; + + public QPosition() { + } + + public QPosition(int index, double weight) { + this.index = index; + this.weight = weight; + } + + public QPosition set(int index, double weight) { + this.index = index; + this.weight = weight; + return this; + } + + } // class Position + + public static final class SplineFunction { + + public PolynomialSplineFunction spline; + public double [] splineQs; + public double [] splineWs; + + public SplineFunction( + PolynomialSplineFunction spline, + double [] splineQs, + double [] splineWs + ) { + this.spline = spline; + this.splineQs = splineQs; + this.splineWs = splineWs; + } + + public double [][] sample( + int numSamples, + double km, + Calculation errors + ) { + double minQ = getQMin(); + double maxQ = getQMax(); + + double [] outWs = new double[numSamples]; + double [] outQs = new double[numSamples]; + + Arrays.fill(outWs, Double.NaN); + Arrays.fill(outQs, Double.NaN); + + double stepWidth = (maxQ - minQ)/numSamples; + + try { + double q = minQ; + for (int i = 0; i < outWs.length; ++i, q += stepWidth) { + outWs[i] = spline.value(outQs[i] = q); + } + } + catch (ArgumentOutsideDomainException aode) { + if (errors != null) { + errors.addProblem(km, "spline.interpolation.failed"); + } + log.error("spline interpolation failed.", aode); + } + + return new double [][] { outWs, outQs }; + } + + public double getQMin() { + return Math.min(splineQs[0], splineQs[splineQs.length-1]); + } + + public double getQMax() { + return Math.max(splineQs[0], splineQs[splineQs.length-1]); + } + + /** Constructs a continues index between the columns to Qs. */ + public PolynomialSplineFunction createIndexQRelation() { + + double [] indices = new double[splineQs.length]; + for (int i = 0; i < indices.length; ++i) { + indices[i] = i; + } + + try { + SplineInterpolator interpolator = new SplineInterpolator(); + return interpolator.interpolate(indices, splineQs); + } + catch (MathIllegalArgumentException miae) { + // Ignore me! + } + return null; + } + } // class SplineFunction + + /** + * A row, typically a position where measurements were taken. + */ + public static final class Row + implements Serializable, Comparable<Row> + { + double km; + double [] ws; + + public Row() { + } + + public Row(double km) { + this.km = km; + } + + public Row(double km, double [] ws) { + this(km); + this.ws = ws; + } + + /** + * Compare according to place of measurement (km). + */ + public int compareTo(Row other) { + double d = km - other.km; + if (d < -0.0001) return -1; + if (d > 0.0001) return +1; + return 0; + } + + /** + * Interpolate Ws, given Qs and a km. + * + * @param iqs Given ("input") Qs. + * @param ows Resulting ("output") Ws. + * @param table Table of which to use data for interpolation. + */ + public void interpolateW( + Row other, + double km, + double [] iqs, + double [] ows, + WstValueTable table, + Calculation errors + ) { + double kmWeight = Linear.factor(km, this.km, other.km); + + QPosition qPosition = new QPosition(); + + for (int i = 0; i < iqs.length; ++i) { + if (table.getQPosition(km, iqs[i], qPosition) != null) { + double wt = getW(qPosition); + double wo = other.getW(qPosition); + if (Double.isNaN(wt) || Double.isNaN(wo)) { + if (errors != null) { + errors.addProblem( + km, "cannot.find.w.for.q", iqs[i]); + } + ows[i] = Double.NaN; + } + else { + ows[i] = Linear.weight(kmWeight, wt, wo); + } + } + else { + if (errors != null) { + errors.addProblem(km, "cannot.find.q", iqs[i]); + } + ows[i] = Double.NaN; + } + } + } + + + public SplineFunction createSpline( + WstValueTable table, + Calculation errors + ) { + int W = ws.length; + + if (W < 1) { + if (errors != null) { + errors.addProblem(km, "no.ws.found"); + } + return null; + } + + double [] splineQs = new double[W]; + + for (int i = 0; i < W; ++i) { + double sq = table.getQIndex(i, km); + if (Double.isNaN(sq) && errors != null) { + errors.addProblem( + km, "no.q.found.in.column", (i+1)); + } + splineQs[i] = sq; + } + + try { + SplineInterpolator interpolator = new SplineInterpolator(); + PolynomialSplineFunction spline = + interpolator.interpolate(splineQs, ws); + + return new SplineFunction(spline, splineQs, ws); + } + catch (MathIllegalArgumentException miae) { + if (errors != null) { + errors.addProblem(km, "spline.creation.failed"); + } + log.error("spline creation failed", miae); + } + return null; + } + + public SplineFunction createSpline( + Row other, + double km, + WstValueTable table, + Calculation errors + ) { + int W = Math.min(ws.length, other.ws.length); + + if (W < 1) { + if (errors != null) { + errors.addProblem("no.ws.found"); + } + return null; + } + + double factor = Linear.factor(km, this.km, other.km); + + double [] splineQs = new double[W]; + double [] splineWs = new double[W]; + + for (int i = 0; i < W; ++i) { + double wws = Linear.weight(factor, ws[i], other.ws[i]); + double wqs = Linear.weight( + factor, + table.getQIndex(i, km), + table.getQIndex(i, other.km)); + + if (Double.isNaN(wws) || Double.isNaN(wqs)) { + if (errors != null) { + errors.addProblem(km, "cannot.find.w.or.q"); + } + } + + splineWs[i] = wws; + splineQs[i] = wqs; + } + + SplineInterpolator interpolator = new SplineInterpolator(); + + try { + PolynomialSplineFunction spline = + interpolator.interpolate(splineQs, splineWs); + + return new SplineFunction(spline, splineQs, splineWs); + } + catch (MathIllegalArgumentException miae) { + if (errors != null) { + errors.addProblem(km, "spline.creation.failed"); + } + log.error("spline creation failed", miae); + } + + return null; + } + + public double [][] interpolateWQ( + Row other, + double km, + int steps, + WstValueTable table, + Calculation errors + ) { + SplineFunction sf = createSpline(other, km, table, errors); + + return sf != null + ? sf.sample(steps, km, errors) + : new double[2][0]; + } + + + public double [][] interpolateWQ( + int steps, + WstValueTable table, + Calculation errors + ) { + SplineFunction sf = createSpline(table, errors); + + return sf != null + ? sf.sample(steps, km, errors) + : new double[2][0]; + } + + + public double getW(QPosition qPosition) { + int index = qPosition.index; + double weight = qPosition.weight; + + return weight == 1.0 + ? ws[index] + : Linear.weight(weight, ws[index-1], ws[index]); + } + + public double getW( + Row other, + double km, + QPosition qPosition + ) { + double kmWeight = Linear.factor(km, this.km, other.km); + + int index = qPosition.index; + double weight = qPosition.weight; + + double tw, ow; + + if (weight == 1.0) { + tw = ws[index]; + ow = other.ws[index]; + } + else { + tw = Linear.weight(weight, ws[index-1], ws[index]); + ow = Linear.weight(weight, other.ws[index-1], other.ws[index]); + } + + return Linear.weight(kmWeight, tw, ow); + } + + public double [] findQsForW(double w, WstValueTable table) { + + TDoubleArrayList qs = new TDoubleArrayList(); + + if (ws.length > 0 && Math.abs(ws[0]-w) < 0.000001) { + double q = table.getQIndex(0, km); + if (!Double.isNaN(q)) { + qs.add(q); + } + } + + for (int i = 1; i < ws.length; ++i) { + double w2 = ws[i]; + if (Double.isNaN(w2)) { + continue; + } + if (Math.abs(w2-w) < 0.000001) { + double q = table.getQIndex(i, km); + if (!Double.isNaN(q)) { + qs.add(q); + } + continue; + } + double w1 = ws[i-1]; + if (Double.isNaN(w1)) { + continue; + } + + if (w < Math.min(w1, w2) || w > Math.max(w1, w2)) { + continue; + } + + double q1 = table.getQIndex(i-1, km); + double q2 = table.getQIndex(i, km); + if (Double.isNaN(q1) || Double.isNaN(q2)) { + continue; + } + + double q = Linear.linear(w, w1, w2, q1, q2); + qs.add(q); + } + + return qs.toNativeArray(); + } + + public double [] findQsForW( + Row other, + double w, + double km, + WstValueTable table + ) { + TDoubleArrayList qs = new TDoubleArrayList(); + + double factor = Linear.factor(km, this.km, other.km); + + if (ws.length > 0) { + double wt = Linear.weight(factor, ws[0], other.ws[0]); + if (!Double.isNaN(wt)) { + double q = table.getQIndex(0, km); + if (!Double.isNaN(q)) { + qs.add(q); + } + } + } + + for (int i = 1; i < ws.length; ++i) { + double w2 = Linear.weight(factor, ws[i], other.ws[i]); + if (Double.isNaN(w2)) { + continue; + } + if (Math.abs(w2-w) < 0.000001) { + double q = table.getQIndex(i, km); + if (!Double.isNaN(q)) { + qs.add(q); + } + continue; + } + double w1 = Linear.weight(factor, ws[i-1], other.ws[i-1]); + if (Double.isNaN(w1)) { + continue; + } + + if (w < Math.min(w1, w2) || w > Math.max(w1, w2)) { + continue; + } + + double q1 = table.getQIndex(i-1, km); + double q2 = table.getQIndex(i, km); + if (Double.isNaN(q1) || Double.isNaN(q2)) { + continue; + } + + double q = Linear.linear(w, w1, w2, q1, q2); + qs.add(q); + } + + return qs.toNativeArray(); + } + + public double [] getMinMaxW(double [] result) { + double minW = Double.MAX_VALUE; + double maxW = -Double.MAX_VALUE; + for (int i = 0; i < ws.length; ++i) { + double w = ws[i]; + if (w < minW) minW = w; + if (w > maxW) maxW = w; + } + result[0] = minW; + result[1] = maxW; + return result; + } + + public double [] getMinMaxW(Row other, double km, double [] result) { + double [] m1 = this .getMinMaxW(new double [2]); + double [] m2 = other.getMinMaxW(new double [2]); + double factor = Linear.factor(km, this.km, other.km); + result[0] = Linear.weight(factor, m1[0], m2[0]); + result[1] = Linear.weight(factor, m1[1], m2[1]); + return result; + } + } // class Row + + /** Rows in table. */ + protected List<Row> rows; + + /** Columns in table. */ + protected Column [] columns; + + public WstValueTable() { + rows = new ArrayList<Row>(); + } + + public WstValueTable(Column [] columns) { + this(); + this.columns = columns; + } + + public WstValueTable(Column [] columns, List<Row> rows) { + this.columns = columns; + this.rows = rows; + } + + /** Sort rows (by km). */ + public void sortRows() { + Collections.sort(rows); + } + + /** + * @param km Given kilometer. + * @param qs Given Q values. + * @param ws output parameter. + */ + public double [] interpolateW(double km, double [] qs, double [] ws) { + return interpolateW(km, qs, ws, null); + } + + + /** + * @param ws (output parameter), gets returned. + * @return output parameter ws. + */ + public double [] interpolateW( + double km, + double [] qs, + double [] ws, + Calculation errors + ) { + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + QPosition qPosition = new QPosition(); + + if (rowIndex >= 0) { // direct row match + Row row = rows.get(rowIndex); + for (int i = 0; i < qs.length; ++i) { + if (getQPosition(km, qs[i], qPosition) == null) { + if (errors != null) { + errors.addProblem(km, "cannot.find.q", qs[i]); + } + ws[i] = Double.NaN; + } + else { + if (Double.isNaN(ws[i] = row.getW(qPosition)) + && errors != null) { + errors.addProblem( + km, "cannot.find.w.for.q", qs[i]); + } + } + } + } + else { // needs bilinear interpolation + rowIndex = -rowIndex -1; + + if (rowIndex < 1 || rowIndex >= rows.size()) { + // do not extrapolate + Arrays.fill(ws, Double.NaN); + if (errors != null) { + errors.addProblem(km, "km.not.found"); + } + } + else { + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + r1.interpolateW(r2, km, qs, ws, this, errors); + } + } + + return ws; + } + + public double [] getMinMaxQ(double km) { + return getMinMaxQ(km, new double [2]); + } + + public double [] getMinMaxQ(double km, double [] result) { + double minQ = Double.MAX_VALUE; + double maxQ = -Double.MAX_VALUE; + + for (int i = 0; i < columns.length; ++i) { + double q = columns[i].getQRangeTree().findQ(km); + if (!Double.isNaN(q)) { + if (q < minQ) minQ = q; + if (q > maxQ) maxQ = q; + } + } + + if (minQ < Double.MAX_VALUE) { + result[0] = minQ; + result[1] = maxQ; + return result; + } + + return null; + } + + public double [] getMinMaxQ(double from, double to, double step) { + double [] result = new double[2]; + + double minQ = Double.MAX_VALUE; + double maxQ = -Double.MAX_VALUE; + + if (from > to) { + double tmp = from; + from = to; + to = tmp; + } + + step = Math.max(Math.abs(step), 0.0001); + + double d = from; + for (; d <= to; d += step) { + if (getMinMaxQ(d, result) != null) { + if (result[0] < minQ) minQ = result[0]; + if (result[1] > maxQ) maxQ = result[1]; + } + } + + if (d != to) { + if (getMinMaxQ(to, result) != null) { + if (result[0] < minQ) minQ = result[0]; + if (result[1] > maxQ) maxQ = result[1]; + } + } + + return minQ < Double.MAX_VALUE + ? new double [] { minQ, maxQ } + : null; + } + + public double [] getMinMaxW(double km) { + return getMinMaxW(km, new double [2]); + + } + public double [] getMinMaxW(double km, double [] result) { + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { + return rows.get(rowIndex).getMinMaxW(result); + } + + rowIndex = -rowIndex -1; + + if (rowIndex < 1 || rowIndex >= rows.size()) { + // do not extrapolate + return null; + } + + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + + return r1.getMinMaxW(r2, km, result); + } + + public double [] getMinMaxW(double from, double to, double step) { + double [] result = new double[2]; + + double minW = Double.MAX_VALUE; + double maxW = -Double.MAX_VALUE; + + if (from > to) { + double tmp = from; + from = to; + to = tmp; + } + + step = Math.max(Math.abs(step), 0.0001); + + double d = from; + for (; d <= to; d += step) { + if (getMinMaxW(d, result) != null) { + if (result[0] < minW) minW = result[0]; + if (result[1] > maxW) maxW = result[1]; + } + } + + if (d != to) { + if (getMinMaxW(to, result) != null) { + if (result[0] < minW) minW = result[0]; + if (result[1] > maxW) maxW = result[1]; + } + } + + return minW < Double.MAX_VALUE + ? new double [] { minW, maxW } + : null; + } + + /** + * Interpolate W and Q values at a given km. + */ + public double [][] interpolateWQ(double km) { + return interpolateWQ(km, null); + } + + /** + * Interpolate W and Q values at a given km. + * + * @param errors where to store errors. + * + * @return double double array, first index Ws, second Qs. + */ + public double [][] interpolateWQ(double km, Calculation errors) { + return interpolateWQ(km, DEFAULT_Q_STEPS, errors); + } + + + /** + * Interpolate W and Q values at a given km. + */ + public double [][] interpolateWQ(double km, int steps, Calculation errors) { + + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { // direct row match + Row row = rows.get(rowIndex); + return row.interpolateWQ(steps, this, errors); + } + + rowIndex = -rowIndex -1; + + if (rowIndex < 1 || rowIndex >= rows.size()) { + // do not extrapolate + if (errors != null) { + errors.addProblem(km, "km.not.found"); + } + return new double[2][0]; + } + + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + + return r1.interpolateWQ(r2, km, steps, this, errors); + } + + public boolean interpolate( + double km, + double [] out, + QPosition qPosition, + Function qFunction + ) { + int R1 = rows.size()-1; + + out[1] = qFunction.value(getQ(qPosition, km)); + + if (Double.isNaN(out[1])) { + return false; + } + + QPosition nPosition = new QPosition(); + if (getQPosition(km, out[1], nPosition) == null) { + return false; + } + + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { + // direct row match + out[0] = rows.get(rowIndex).getW(nPosition); + return !Double.isNaN(out[0]); + } + + rowIndex = -rowIndex -1; + + if (rowIndex < 1 || rowIndex > R1) { + // do not extrapolate + return false; + } + + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + out[0] = r1.getW(r2, km, nPosition); + + return !Double.isNaN(out[0]); + } + + + /** + * Look up interpolation of a Q at given positions. + * + * @param q the non-interpolated Q value. + * @param referenceKm the reference km (e.g. gauge position). + * @param kms positions for which to interpolate. + * @param ws (output) resulting interpolated ws. + * @param qs (output) resulting interpolated qs. + * @param errors calculation object to store errors. + */ + public QPosition interpolate( + double q, + double referenceKm, + double [] kms, + double [] ws, + double [] qs, + Calculation errors + ) { + return interpolate( + q, referenceKm, kms, ws, qs, 0, kms.length, errors); + } + + public QPosition interpolate( + double q, + double referenceKm, + double [] kms, + double [] ws, + double [] qs, + int startIndex, + int length, + Calculation errors + ) { + QPosition qPosition = getQPosition(referenceKm, q); + + if (qPosition == null) { + // we cannot locate q at km + Arrays.fill(ws, Double.NaN); + Arrays.fill(qs, Double.NaN); + if (errors != null) { + errors.addProblem(referenceKm, "cannot.find.q", q); + } + return null; + } + + Row kmKey = new Row(); + + int R1 = rows.size()-1; + + for (int i = startIndex, end = startIndex+length; i < end; ++i) { + + if (Double.isNaN(qs[i] = getQ(qPosition, kms[i]))) { + if (errors != null) { + errors.addProblem(kms[i], "cannot.find.q", q); + } + ws[i] = Double.NaN; + continue; + } + + kmKey.km = kms[i]; + int rowIndex = Collections.binarySearch(rows, kmKey); + + if (rowIndex >= 0) { + // direct row match + if (Double.isNaN(ws[i] = rows.get(rowIndex).getW(qPosition)) + && errors != null) { + errors.addProblem(kms[i], "cannot.find.w.for.q", q); + } + continue; + } + + rowIndex = -rowIndex -1; + + if (rowIndex < 1 || rowIndex > R1) { + // do not extrapolate + if (errors != null) { + errors.addProblem(kms[i], "km.not.found"); + } + ws[i] = Double.NaN; + continue; + } + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + + if (Double.isNaN(ws[i] = r1.getW(r2, kms[i], qPosition)) + && errors != null) { + errors.addProblem(kms[i], "cannot.find.w.for.q", q); + } + } + + return qPosition; + } + + /** + * Linearly interpolate w at a km at a column of two rows. + * + * @param km position for which to interpolate. + * @param row1 first row. + * @param row2 second row. + * @param col column-index at which to look. + * + * @return Linearly interpolated w, NaN if one of the given rows was null. + */ + public static double linearW(double km, Row row1, Row row2, int col) { + if (row1 == null || row2 == null) { + return Double.NaN; + } + + return Linear.linear(km, + row1.km, row2.km, + row1.ws[col], row2.ws[col]); + } + + /** + * Do interpolation/lookup of W and Q within columns (i.e. ignoring values + * of other columns). + * @param km position (km) at which to interpolate/lookup. + * @return [[q0, q1, .. qx] , [w0, w1, .. wx]] (can contain NaNs) + */ + public double [][] interpolateWQColumnwise(double km) { + log.debug("WstValueTable.interpolateWQColumnwise"); + double [] qs = new double[columns.length]; + double [] ws = new double[columns.length]; + + // Find out row from where we will start searching. + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex < 0) { + rowIndex = -rowIndex -1; + } + + // TODO Beyond definition, we could stop more clever. + if (rowIndex >= rows.size()) { + rowIndex = rows.size() -1; + } + + Row startRow = rows.get(rowIndex); + + for (int col = 0; col < columns.length; col++) { + qs[col] = columns[col].getQRangeTree().findQ(km); + if (startRow.km == km && startRow.ws[col] != Double.NaN) { + // Great. W is defined at km. + ws[col] = startRow.ws[col]; + continue; + } + + // Search neighbouring rows that define w at this col. + Row rowBefore = null; + Row rowAfter = null; + for (int before = rowIndex -1; before >= 0; before--) { + if (!Double.isNaN(rows.get(before).ws[col])) { + rowBefore = rows.get(before); + break; + } + } + if (rowBefore != null) { + for (int after = rowIndex, R = rows.size(); after < R; after++) { + if (!Double.isNaN(rows.get(after).ws[col])) { + rowAfter = rows.get(after); + break; + } + } + } + + ws[col] = linearW(km, rowBefore, rowAfter, col); + } + + return new double [][] {qs, ws}; + } + + public double [] findQsForW(double km, double w) { + + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { + return rows.get(rowIndex).findQsForW(w, this); + } + + rowIndex = -rowIndex - 1; + + if (rowIndex < 1 || rowIndex >= rows.size()) { + // Do not extrapolate. + return new double[0]; + } + + // Needs bilinear interpolation. + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + + return r1.findQsForW(r2, w, km, this); + } + + protected SplineFunction createSpline(double km, Calculation errors) { + + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { + SplineFunction sf = rows.get(rowIndex).createSpline(this, errors); + if (sf == null && errors != null) { + errors.addProblem(km, "cannot.create.wq.relation"); + } + return sf; + } + + rowIndex = -rowIndex - 1; + + if (rowIndex < 1 || rowIndex >= rows.size()) { + // Do not extrapolate. + if (errors != null) { + errors.addProblem(km, "km.not.found"); + } + return null; + } + + // Needs bilinear interpolation. + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + + SplineFunction sf = r1.createSpline(r2, km, this, errors); + if (sf == null && errors != null) { + errors.addProblem(km, "cannot.create.wq.relation"); + } + + return sf; + } + + /** 'Bezugslinienverfahren' */ + public double [][] relateWs( + double km1, + double km2, + Calculation errors + ) { + return relateWs(km1, km2, RELATE_WS_SAMPLES, errors); + } + + private static class ErrorHandler { + + boolean hasErrors; + Calculation errors; + + ErrorHandler(Calculation errors) { + this.errors = errors; + } + + void error(double km, String key, Object ... args) { + if (errors != null && !hasErrors) { + hasErrors = true; + errors.addProblem(km, key, args); + } + } + } // class ErrorHandler + + + /* TODO: Add optimized methods of relateWs to relate one + * start km to many end kms. The index generation/spline stuff for + * the start km is always the same. + */ + public double [][] relateWs( + double km1, + double km2, + int numSamples, + Calculation errors + ) { + SplineFunction sf1 = createSpline(km1, errors); + if (sf1 == null) { + return new double[2][0]; + } + + SplineFunction sf2 = createSpline(km2, errors); + if (sf2 == null) { + return new double[2][0]; + } + + PolynomialSplineFunction iQ1 = sf1.createIndexQRelation(); + if (iQ1 == null) { + if (errors != null) { + errors.addProblem(km1, "cannot.create.index.q.relation"); + } + return new double[2][0]; + } + + PolynomialSplineFunction iQ2 = sf2.createIndexQRelation(); + if (iQ2 == null) { + if (errors != null) { + errors.addProblem(km2, "cannot.create.index.q.relation"); + } + return new double[2][0]; + } + + int N = Math.min(sf1.splineQs.length, sf2.splineQs.length); + double stepWidth = N/(double)numSamples; + + PolynomialSplineFunction qW1 = sf1.spline; + PolynomialSplineFunction qW2 = sf2.spline; + + TDoubleArrayList ws1 = new TDoubleArrayList(numSamples); + TDoubleArrayList ws2 = new TDoubleArrayList(numSamples); + TDoubleArrayList qs1 = new TDoubleArrayList(numSamples); + TDoubleArrayList qs2 = new TDoubleArrayList(numSamples); + + ErrorHandler err = new ErrorHandler(errors); + + int i = 0; + for (double p = 0d; p <= N-1; p += stepWidth, ++i) { + + double q1; + try { + q1 = iQ1.value(p); + } + catch (ArgumentOutsideDomainException aode) { + err.error(km1, "w.w.qkm1.failed", p); + continue; + } + + double w1; + try { + w1 = qW1.value(q1); + } + catch (ArgumentOutsideDomainException aode) { + err.error(km1, "w.w.wkm1.failed", q1, p); + continue; + } + + double q2; + try { + q2 = iQ2.value(p); + } + catch (ArgumentOutsideDomainException aode) { + err.error(km2, "w.w.qkm2.failed", p); + continue; + } + + double w2; + try { + w2 = qW2.value(q2); + } + catch (ArgumentOutsideDomainException aode) { + err.error(km2, "w.w.wkm2.failed", q2, p); + continue; + } + + ws1.add(w1); + ws2.add(w2); + qs1.add(q1); + qs2.add(q2); + } + + return new double [][] { + ws1.toNativeArray(), + qs1.toNativeArray(), + ws2.toNativeArray(), + qs2.toNativeArray() }; + } + + public QPosition getQPosition(double km, double q) { + return getQPosition(km, q, new QPosition()); + } + + public QPosition getQPosition(double km, double q, QPosition qPosition) { + + if (columns.length == 0) { + return null; + } + + double qLast = columns[0].getQRangeTree().findQ(km); + + if (Math.abs(qLast - q) < 0.00001) { + return qPosition.set(0, 1d); + } + + for (int i = 1; i < columns.length; ++i) { + double qCurrent = columns[i].getQRangeTree().findQ(km); + if (Math.abs(qCurrent - q) < 0.00001) { + return qPosition.set(i, 1d); + } + + double qMin, qMax; + if (qLast < qCurrent) { qMin = qLast; qMax = qCurrent; } + else { qMin = qCurrent; qMax = qLast; } + + if (q > qMin && q < qMax) { + double weight = Linear.factor(q, qLast, qCurrent); + return qPosition.set(i, weight); + } + qLast = qCurrent; + } + + return null; + } + + public double getQIndex(int index, double km) { + return columns[index].getQRangeTree().findQ(km); + } + + public double getQ(QPosition qPosition, double km) { + int index = qPosition.index; + double weight = qPosition.weight; + + if (weight == 1d) { + return columns[index].getQRangeTree().findQ(km); + } + double q1 = columns[index-1].getQRangeTree().findQ(km); + double q2 = columns[index ].getQRangeTree().findQ(km); + return Linear.weight(weight, q1, q2); + } + + public double [][] interpolateTabulated(double km) { + return interpolateTabulated(km, new double[2][columns.length]); + } + + public double [][] interpolateTabulated(double km, double [][] result) { + + int rowIndex = Collections.binarySearch(rows, new Row(km)); + + if (rowIndex >= 0) { + // Direct hit -> copy ws. + Row row = rows.get(rowIndex); + System.arraycopy( + row.ws, 0, result[0], 0, + Math.min(row.ws.length, result[0].length)); + } + else { + rowIndex = -rowIndex -1; + if (rowIndex < 1 || rowIndex >= rows.size()) { + // Out of bounds. + return null; + } + // Interpolate ws. + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + double factor = Linear.factor(km, r1.km, r2.km); + Linear.weight(factor, r1.ws, r2.ws, result[0]); + } + + double [] qs = result[1]; + for (int i = Math.min(qs.length, columns.length)-1; i >= 0; --i) { + qs[i] = columns[i].getQRangeTree().findQ(km); + } + return result; + } + + public List<Range> findSegments(double km1, double km2) { + return columns.length != 0 + ? columns[columns.length-1].getQRangeTree().findSegments(km1, km2) + : Collections.<Range>emptyList(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableCacheKey.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,33 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +/** + * Cache Key (identifier) for WstValueTables. + */ +public final class WstValueTableCacheKey +implements Serializable +{ + public static final String CACHE_NAME = "wst-value-table"; + + private int riverId; + private int kind; + + public WstValueTableCacheKey(int riverId, int kind) { + this.riverId = riverId; + this.kind = kind; + } + + public int hashCode() { + return (riverId << 8) | kind; + } + + public boolean equals(Object other) { + if (!(other instanceof WstValueTableCacheKey)) { + return false; + } + WstValueTableCacheKey o = (WstValueTableCacheKey)other; + return riverId == o.riverId && kind == o.kind; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,469 @@ +package de.intevation.flys.artifacts.model; + +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import org.apache.log4j.Logger; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Wst; + +import org.hibernate.Session; +import org.hibernate.Query; +import org.hibernate.SQLQuery; + +import org.hibernate.type.StandardBasicTypes; + +/** + * Creates WstValueTable s from database. + * WstValueTable s are used to interpolate given w/q/km values. + */ +public class WstValueTableFactory +{ + private static Logger log = Logger.getLogger(WstValueTableFactory.class); + + public static final int DEFAULT_KIND = 0; + + // TODO: put this into a property file + + public static final String HQL_WST = + "from Wst where river=:river and kind=:kind"; + + public static final String SQL_SELECT_NAMES_POS = + "SELECT position, name FROM wst_columns " + + "WHERE wst_id = :wst_id ORDER BY position"; + + /** Select Qs for wst (view sorted by column). */ + public static final String SQL_SELECT_QS = + "SELECT column_pos, q, a, b FROM wst_q_values " + + "WHERE wst_id = :wst_id"; + + // (sorted by km) + public static final String SQL_SELECT_WS = + "SELECT km, w, column_pos FROM wst_w_values " + + "WHERE wst_id = :wst_id"; + + /** Statement to query qranges of a single column. */ + public static final String SQL_SELECT_QS_AT_COL = + "SELECT q, a, b FROM wst_q_values " + + "WHERE wst_id = :wst_id AND column_pos = :column_pos"; + + // (sorted by km) + public static final String SQL_SELECT_WS_AT_COL = + "SELECT km, w FROM wst_w_values " + + "WHERE wst_id = :wst_id AND column_pos = :column_pos"; + + + private WstValueTableFactory() { + } + + + public static WstValueTable getTable(River river) { + return getTable(river, DEFAULT_KIND); + } + + + /** + * Get WstValueTable to interpolate values of a given Wst. + */ + public static WstValueTable getTable(int wst_id) { + + Cache cache = CacheFactory.getCache(WstValueTableCacheKey.CACHE_NAME); + + WstValueTableCacheKey cacheKey; + + if (cache != null) { + // "-1" is the symbolic river-id for "no river, but wst_id". + cacheKey = new WstValueTableCacheKey(-1, wst_id); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("Got specific wst value table from cache"); + return (WstValueTable) element.getValue(); + } + } + else { + cacheKey = null; + } + + Session session = SessionHolder.HOLDER.get(); + + // Fetch data for one column only. + + WstValueTable.Column [] columns = loadColumns(session, wst_id); + loadQRanges(session, columns, wst_id); + List<WstValueTable.Row> rows = loadRows(session, wst_id, columns.length); + + WstValueTable valueTable = new WstValueTable(columns, rows); + + if (valueTable != null && cacheKey != null) { + log.debug("Store wst value table in cache"); + Element element = new Element(cacheKey, valueTable); + cache.put(element); + } + + return valueTable; + } + + /** + * Get Table for a specific column of a wst. + */ + public static WstValueTable getWstColumnTable(int wst_id, int col_pos) { + + Cache cache = CacheFactory.getCache(WstValueTableCacheKey.CACHE_NAME); + + WstValueTableCacheKey cacheKey; + + if (cache != null) { + // A negaitve/negative number is the symbolic 'river-id' for + // "no river and kind but wst_id and colpos". + cacheKey = new WstValueTableCacheKey(-wst_id, -col_pos); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("Got specific wst value table from cache"); + return (WstValueTable) element.getValue(); + } + } + else { + cacheKey = null; + } + + Session session = SessionHolder.HOLDER.get(); + + // Fetch data for one column only. + + WstValueTable.Column [] columns = loadColumn(session, wst_id, col_pos); + loadQRanges(session, columns, wst_id, col_pos); + List<WstValueTable.Row> rows = loadRowsOneColumn(session, wst_id, col_pos); + + WstValueTable valueTable = new WstValueTable(columns, rows); + + if (valueTable != null && cacheKey != null) { + log.debug("Store wst value table in cache (wst: " + + wst_id + "/ col: " + col_pos + ")"); + Element element = new Element(cacheKey, valueTable); + cache.put(element); + } + + return valueTable; + } + + + /** + * Get table for first wst of given kind at given river. + */ + public static WstValueTable getTable(River river, int kind) { + + Cache cache = CacheFactory.getCache(WstValueTableCacheKey.CACHE_NAME); + + WstValueTableCacheKey cacheKey; + + if (cache != null) { + cacheKey = new WstValueTableCacheKey(river.getId(), kind); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("got wst value table from cache"); + return (WstValueTable)element.getValue(); + } + } + else { + cacheKey = null; + } + + WstValueTable valueTable = getTableUncached(river, kind); + + if (valueTable != null && cacheKey != null) { + log.debug("store wst value table in cache"); + Element element = new Element(cacheKey, valueTable); + cache.put(element); + } + + return valueTable; + } + + public static WstValueTable getTableUncached(River river) { + return getTableUncached(river, DEFAULT_KIND); + } + + public static WstValueTable getTableUncached(River river, int kind) { + + Session session = SessionHolder.HOLDER.get(); + + Wst wst = loadWst(session, river, kind); + + if (wst == null) { + return null; + } + + WstValueTable.Column [] columns = loadColumns(session, wst); + + loadQRanges(session, columns, wst); + + List<WstValueTable.Row> rows = loadRows(session, wst, columns.length); + + return new WstValueTable(columns, rows); + } + + /** + * @param kind Kind of wst. + */ + protected static Wst loadWst(Session session, River river, int kind) { + Query query = session.createQuery(HQL_WST); + query.setParameter("river", river); + query.setInteger("kind", kind); + + List<Wst> wsts = query.list(); + + // TODO Multiple wsts can match, why return just the first one? + return wsts.isEmpty() ? null : wsts.get(0); + } + + + /** + * Load rows with a single columns result. + * + * @param session session to use for querying db. + * @param wstId id of wst (in db). + * @param column_pos the column_pos (within the db) of the wst_value_table + * of which the values shall be fetched. + * + * @return resultant rows. + */ + protected static List<WstValueTable.Row> loadRowsOneColumn( + Session session, + int wstId, + int column_pos + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WS_AT_COL) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("w", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("wst_id", wstId); + sqlQuery.setInteger("column_pos", column_pos); + + List<Object []> results = sqlQuery.list(); + + double [] ws = null; + + List<WstValueTable.Row> rows = + new ArrayList<WstValueTable.Row>(results.size()); + + // Walk over rows. + for (Object [] result: results) { + ws = new double[1]; + WstValueTable.Row row = + new WstValueTable.Row((Double) result[0], ws); + rows.add(row); + + Double w = (Double) result[1]; + ws[0] = w != null ? w : Double.NaN; + } + + return rows; + } + + protected static List<WstValueTable.Row> loadRows( + Session session, + int wst_id, + int numColumns + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WS) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("w", StandardBasicTypes.DOUBLE) + .addScalar("column_pos", StandardBasicTypes.INTEGER); + + sqlQuery.setInteger("wst_id", wst_id); + + List<Object []> results = sqlQuery.list(); + + int lastColumn = Integer.MAX_VALUE; + double [] ws = null; + + ArrayList<WstValueTable.Row> rows = new ArrayList<WstValueTable.Row>(); + + for (Object [] result: results) { + int column = (Integer)result[2]; + if (column < lastColumn) { + ws = new double[numColumns]; + Arrays.fill(ws, Double.NaN); + WstValueTable.Row row = + new WstValueTable.Row((Double)result[0], ws); + rows.add(row); + } + Double w = (Double)result[1]; + ws[column] = w != null ? w : Double.NaN; + lastColumn = column; + } + + rows.trimToSize(); + return rows; + } + + protected static List<WstValueTable.Row> loadRows( + Session session, + Wst wst, + int numColumns + ) { + return loadRows(session, wst.getId(), numColumns); + } + + + protected static WstValueTable.Column [] loadColumn( + Session session, + int wst_id, + int col_pos + ) { + return new WstValueTable.Column [] { + new WstValueTable.Column(WKmsFactory.getWKmsName(col_pos, wst_id))}; + } + + + /** + * Get columns from wst-id. + */ + protected static WstValueTable.Column [] loadColumns( + Session session, + int wst_id + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_NAMES_POS) + .addScalar("position", StandardBasicTypes.INTEGER) + .addScalar("name", StandardBasicTypes.STRING); + + sqlQuery.setInteger("wst_id", wst_id); + + List<Object []> columnNames = sqlQuery.list(); + + WstValueTable.Column [] columns = + new WstValueTable.Column[columnNames.size()]; + + for (int i = 0; i < columns.length; ++i) { + columns[i] = new WstValueTable.Column( + (String)columnNames.get(i)[1]); + } + return columns; + } + + /** + * Get columns from Wst. + */ + protected static WstValueTable.Column [] loadColumns( + Session session, + Wst wst + ) { + return loadColumns(session, wst.getId()); + } + + + /** + * Build a QRange-Tree. + */ + protected static void loadQRanges( + Session session, + WstValueTable.Column [] columns, + int wst_id, + int column_pos + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_QS_AT_COL) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("wst_id", wst_id); + sqlQuery.setInteger("column_pos", column_pos); + + List<Object []> qRanges = sqlQuery.list(); + + int qSize = qRanges.size(); + + QRangeTree qRangeTree = new QRangeTree( + qRanges, QRangeTree.WITHOUT_COLUMN, 0, qSize); + columns[0].setQRangeTree(qRangeTree); + } + + protected static void loadQRanges( + Session session, + WstValueTable.Column [] columns, + int wst_id + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_QS) + .addScalar("column_pos", StandardBasicTypes.INTEGER) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("wst_id", wst_id); + + List<Object []> qRanges = sqlQuery.list(); + + int start = -1; + int Q = qRanges.size(); + Integer lastColumn = null; + + for (int i = 0; i < Q; ++i) { + Object [] qRange = qRanges.get(i); + Integer columnId = (Integer)qRange[0]; + if (lastColumn == null) { + lastColumn = columnId; + start = i; + } + else if (!lastColumn.equals(columnId)) { + QRangeTree qRangeTree = new QRangeTree(qRanges, start, i); + columns[lastColumn].setQRangeTree(qRangeTree); + lastColumn = columnId; + start = i; + } + } + + if (start != -1) { + QRangeTree qRangeTree = new QRangeTree(qRanges, start, Q); + columns[lastColumn].setQRangeTree(qRangeTree); + } + + /* This is debug code to visualize the q ranges trees + + java.io.PrintWriter out = null; + try { + out = new java.io.PrintWriter( + new java.io.FileWriter( + "/tmp/qranges" + System.currentTimeMillis() + ".dot")); + + out.println("graph \"Q ranges trees\" {"); + + for (int i = 0; i < columns.length; ++i) { + QRangeTree tree = columns[i].getQRangeTree(); + out.println(tree.toGraph()); + } + + out.println("}"); + + out.flush(); + } + catch (java.io.IOException ioe) { + log.error(ioe); + } + finally { + if (out != null) { + out.close(); + } + } + */ + + } + + protected static void loadQRanges( + Session session, + WstValueTable.Column [] columns, + Wst wst + ) { + loadQRanges(session, columns, wst.getId()); + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,107 @@ +package de.intevation.flys.artifacts.model.extreme; + +import de.intevation.flys.artifacts.math.Function; +import de.intevation.flys.artifacts.math.NaNFunction; +import de.intevation.flys.artifacts.math.UnivariateRealFunctionFunction; + +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import java.io.Serializable; + +import java.lang.ref.SoftReference; + +import org.apache.commons.math.analysis.interpolation.SplineInterpolator; + +import org.apache.commons.math.exception.MathIllegalArgumentException; + +import org.apache.log4j.Logger; + +public class Curve +implements Serializable, Function +{ + private static Logger log = Logger.getLogger(Curve.class); + + protected double [] qs; + protected double [] ws; + protected String function; + protected double [] coeffs; + + // The spline is pretty heavy weight so cache it with a soft ref only. + protected transient SoftReference<Function> spline; + protected transient Function extrapolation; + + public Curve() { + } + + public Curve( + double [] qs, + double [] ws, + String function, + double [] coeffs + ) { + this.qs = qs; + this.ws = ws; + this.function = function; + this.coeffs = coeffs; + } + + public double [] getQs() { + return qs; + } + + public double [] getWs() { + return ws; + } + + public String getFunction() { + return function; + } + + public double [] getCoeffs() { + return coeffs; + } + + @Override + public double value(double x) { + if (x < qs[0]) return Double.NaN; + return (x <= qs[qs.length-1] + ? getSpline() + : getExtrapolation()).value(x); + } + + protected synchronized Function getExtrapolation() { + if (extrapolation == null) { + de.intevation.flys.artifacts.math.fitting.Function + f = FunctionFactory.getInstance().getFunction(function); + + extrapolation = f != null + ? f.instantiate(coeffs) + : NaNFunction.INSTANCE; + } + return extrapolation; + } + + protected synchronized Function getSpline() { + Function sp; + if (spline != null) { + if ((sp = spline.get()) != null) { + return sp; + } + } + spline = new SoftReference<Function>(sp = createSpline()); + return sp; + } + + protected Function createSpline() { + SplineInterpolator interpolator = new SplineInterpolator(); + try { + return new UnivariateRealFunctionFunction( + interpolator.interpolate(qs, ws)); + } + catch (MathIllegalArgumentException miae) { + log.debug("creation on spline failed", miae); + return NaNFunction.INSTANCE; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.artifacts.model.extreme; + +import de.intevation.flys.artifacts.access.ExtremeAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.RangeWithValues; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.artifacts.model.WstValueTable; +import de.intevation.flys.artifacts.model.WstValueTableFactory; + +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.DoubleUtil; + +import java.util.List; + +public class ExtremeCalculation +extends Calculation +{ + protected String river; + protected String function; + protected double from; + protected double to; + protected double step; + protected double percent; + protected List<RangeWithValues> ranges; + + public ExtremeCalculation() { + } + + public ExtremeCalculation(ExtremeAccess access) { + String river = access.getRiver(); + String function = access.getFunction(); + Double from = access.getFrom(); + Double to = access.getTo(); + Double step = access.getStep(); + Double percent = access.getPercent(); + List<RangeWithValues> ranges = access.getRanges(); + + if (river == null) { + // TODO: i18n + addProblem("extreme.no.river"); + } + + if (function == null) { + // TODO: i18n + addProblem("extreme.no.function"); + } + + if (from == null) { + // TODO: i18n + addProblem("extreme.no.from"); + } + + if (to == null) { + // TODO: i18n + addProblem("extreme.no.to"); + } + + if (step == null) { + // TODO: i18n + addProblem("extreme.no.step"); + } + + if (percent == null) { + // TODO: i18n + addProblem("extreme.no.percent"); + } + + if (ranges == null) { + // TODO: i18n + addProblem("extreme.no.ranges"); + } + + if (!hasProblems()) { + this.river = river; + this.function = function; + this.from = Math.min(from, to); + this.to = Math.max(from, to); + this.step = Math.max(0.001d, Math.abs(step)/1000d); + this.percent = Math.max(0d, Math.min(100d, percent)); + this.ranges = ranges; + } + } + + public CalculationResult calculate() { + + WstValueTable wst = null; + + River river = RiverFactory.getRiver(this.river); + if (river == null) { + // TODO: i18n + addProblem("extreme.no.such.river", this.river); + } + else { + wst = WstValueTableFactory.getTable(river); + if (wst == null) { + // TODO: i18n + addProblem("extreme.no.wst.table"); + } + } + + Function function = + FunctionFactory.getInstance().getFunction(this.function); + if (function == null) { + // TODO: i18n + addProblem("extreme.no.such.function", this.function); + } + + return hasProblems() + ? new CalculationResult(this) + : innerCalculate(wst, function); + } + + protected CalculationResult innerCalculate( + WstValueTable wst, + Function function + ) { + RangeWithValues range = null; + + KMs: for (double km = from; km <= to; km += step) { + double currentKm = DoubleUtil.round(km); + + if (range == null || !range.inside(currentKm)) { + for (RangeWithValues r: ranges) { + if (r.inside(currentKm)) { + range = r; + break; + } + } + // TODO: i18n + addProblem(currentKm, "extreme.no.range"); + continue KMs; + } + + double [][] wqs = wst.interpolateTabulated(currentKm); + if (wqs == null) { + // TODO: i18n + addProblem(currentKm, "extreme.no.raw.data"); + continue; + } + + // XXX: This should not be necessary for model data. + if (!DoubleUtil.isValid(wqs)) { + // TODO: i18n + addProblem(currentKm, "extreme.invalid.data"); + continue; + } + // TODO: Implement extraction of points for curve fitting. + // TODO: Implement curve fitting. + // TODO: Implement generating Curve object per km. + } + + ExtremeResult result = new ExtremeResult(); + return new CalculationResult(result, this); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,11 @@ +package de.intevation.flys.artifacts.model.extreme; + +import java.io.Serializable; + +public class ExtremeResult +implements Serializable +{ + public ExtremeResult() { + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,98 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.model.DateRange; + +import java.io.Serializable; + +public class AnalysisPeriod +implements Serializable +{ + protected DateRange dateRange; + protected QWD [] qwds; + protected QWD [] qSectorAverages; + protected double [] qSectorStdDevs; + + public AnalysisPeriod() { + } + + public AnalysisPeriod(DateRange dateRange) { + this.dateRange = dateRange; + } + + public AnalysisPeriod(DateRange dateRange, QWD [] qwds) { + this(dateRange); + this.dateRange = dateRange; + this.qwds = qwds; + } + + public AnalysisPeriod( + DateRange dateRange, + QWD [] qwds, + QWD [] qSectorAverages, + double [] qSectorStdDevs + ) { + this(dateRange, qwds); + this.qSectorAverages = qSectorAverages; + this.qSectorStdDevs = qSectorStdDevs; + } + + public DateRange getDateRange() { + return dateRange; + } + + public void setDateRange(DateRange dateRange) { + this.dateRange = dateRange; + } + + public QWD [] getQWDs() { + return qwds; + } + + public void setQWDs(QWD [] qwds) { + this.qwds = qwds; + } + + public QWD [] getQSectorAverages() { + return qSectorAverages; + } + + public void setQSectorAverages(QWD [] qSectorAverages) { + this.qSectorAverages = qSectorAverages; + } + + public QWD getQSectorAverage(int i) { + return qSectorAverages[i]; + } + + public double [] getQSectorStdDevs() { + return qSectorStdDevs; + } + + public void setQSectorStdDevs(double [] qSectorStdDevs) { + this.qSectorStdDevs = qSectorStdDevs; + } + + public double getQSectorStdDev(int i) { + return qSectorStdDevs[i]; + } + + public double getMaxQ() { + double maxQ = -Double.MAX_VALUE; + if (qwds != null) { + for (QWD qwd: qwds) { + if (qwd.getQ() > maxQ) { + maxQ = qwd.getQ(); + } + } + } + if (qSectorAverages != null) { + for (QWD qwd: qSectorAverages) { + if (qwd != null && qwd.getQ() > maxQ) { + maxQ = qwd.getQ(); + } + } + } + return maxQ; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,247 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.math.Outlier; + +import de.intevation.flys.artifacts.math.fitting.Function; + +import gnu.trove.TDoubleArrayList; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.math.MathException; + +import org.apache.commons.math.optimization.fitting.CurveFitter; + +import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; + +import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; + +import org.apache.log4j.Logger; + +public class Fitting +{ + private static Logger log = Logger.getLogger(Fitting.class); + + /** Use instance of this factory to find meta infos for outliers. */ + public interface QWDFactory { + + QWD create(double q, double w); + + } // interface QWFactory + + public static final QWDFactory QWD_FACTORY = new QWDFactory() { + @Override + public QWD create(double q, double w) { + return new QWD(q, w); + } + }; + + protected boolean checkOutliers; + protected Function function; + protected QWDFactory qwdFactory; + protected double chiSqr; + protected double [] parameters; + protected ArrayList<QWI> removed; + protected QWD [] referenced; + protected double standardDeviation; + + + public Fitting() { + removed = new ArrayList<QWI>(); + } + + public Fitting(Function function) { + this(function, QWD_FACTORY); + } + + public Fitting(Function function, QWDFactory qwdFactory) { + this(function, qwdFactory, false); + } + + public Fitting( + Function function, + QWDFactory qwdFactory, + boolean checkOutliers + ) { + this(); + this.function = function; + this.qwdFactory = qwdFactory; + this.checkOutliers = checkOutliers; + } + + public Function getFunction() { + return function; + } + + public void setFunction(Function function) { + this.function = function; + } + + public boolean getCheckOutliers() { + return checkOutliers; + } + + public void setCheckOutliers(boolean checkOutliers) { + this.checkOutliers = checkOutliers; + } + + public double getChiSquare() { + return chiSqr; + } + + public void reset() { + chiSqr = 0.0; + parameters = null; + removed.clear(); + referenced = null; + standardDeviation = 0.0; + } + + public boolean hasOutliers() { + return !removed.isEmpty(); + } + + public List<QWI> getOutliers() { + return removed; + } + + public QWI [] outliersToArray() { + return removed.toArray(new QWI[removed.size()]); + } + + public QWD [] referencedToArray() { + return referenced != null ? (QWD [])referenced.clone() : null; + } + + public double getMaxQ() { + double maxQ = -Double.MAX_VALUE; + if (referenced != null) { + for (QWI qw: referenced) { + if (qw.getQ() > maxQ) { + maxQ = qw.getQ(); + } + } + } + return maxQ; + } + + public double [] getParameters() { + return parameters; + } + + public double getStandardDeviation() { + return standardDeviation; + } + + public boolean fit(double [] qs, double [] ws) { + + TDoubleArrayList xs = new TDoubleArrayList(qs.length); + TDoubleArrayList ys = new TDoubleArrayList(ws.length); + + for (int i = 0; i < qs.length; ++i) { + if (!Double.isNaN(qs[i]) && !Double.isNaN(ws[i])) { + xs.add(qs[i]); + ys.add(ws[i]); + } + else { + log.warn("remove invalid value " + qs[i] + " " + ws[i]); + } + } + + if (xs.size() < 2) { + log.warn("Too less points."); + return false; + } + + List<Double> inputs = new ArrayList<Double>(xs.size()); + + de.intevation.flys.artifacts.math.Function instance = null; + + LevenbergMarquardtOptimizer lmo = null; + + for (;;) { + parameters = null; + for (double tolerance = 1e-10; tolerance < 1e-3; tolerance *= 10d) { + + lmo = new LevenbergMarquardtOptimizer(); + lmo.setCostRelativeTolerance(tolerance); + lmo.setOrthoTolerance(tolerance); + lmo.setParRelativeTolerance(tolerance); + + CurveFitter cf = new CurveFitter(lmo); + + for (int i = 0, N = xs.size(); i < N; ++i) { + cf.addObservedPoint(xs.getQuick(i), ys.getQuick(i)); + } + + try { + parameters = cf.fit(function, function.getInitialGuess()); + break; + } + catch (MathException me) { + if (log.isDebugEnabled()) { + log.debug("tolerance " + tolerance + " + failed."); + } + } + } + if (parameters == null) { + return false; + } + + // This is the paraterized function for a given km. + instance = function.instantiate(parameters); + + if (!checkOutliers) { + break; + } + + inputs.clear(); + + for (int i = 0, N = xs.size(); i < N; ++i) { + double y = instance.value(xs.getQuick(i)); + if (Double.isNaN(y)) { + y = Double.MAX_VALUE; + } + inputs.add(Double.valueOf(ys.getQuick(i) - y)); + } + + Integer outlier = Outlier.findOutlier(inputs); + + if (outlier == null) { + break; + } + + int idx = outlier.intValue(); + removed.add( + qwdFactory.create( + xs.getQuick(idx), ys.getQuick(idx))); + xs.remove(idx); + ys.remove(idx); + } + + StandardDeviation stdDev = new StandardDeviation(); + + referenced = new QWD[xs.size()]; + for (int i = 0; i < referenced.length; ++i) { + QWD qwd = qwdFactory.create(xs.getQuick(i), ys.getQuick(i)); + + if (qwd == null) { + log.warn("QW creation failed!"); + } + else { + referenced[i] = qwd; + double dw = (qwd.getW() - instance.value(qwd.getQ()))*100.0; + qwd.setDeltaW(dw); + stdDev.increment(dw); + } + } + + standardDeviation = stdDev.getResult(); + + chiSqr = lmo.getChiSquare(); + + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,293 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DateRange; + +import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; +import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter; + +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.Parameters; +import de.intevation.flys.artifacts.model.Range; + +import de.intevation.flys.utils.DateAverager; +import de.intevation.flys.utils.KMIndex; + +import gnu.trove.TIntIntHashMap; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; + +import org.apache.log4j.Logger; + +public class FixAnalysisCalculation +extends FixCalculation +{ + private static Logger log = Logger.getLogger(FixAnalysisCalculation.class); + + protected DateRange referencePeriod; + protected DateRange [] analysisPeriods; + + public FixAnalysisCalculation() { + } + + public FixAnalysisCalculation(FixAnalysisAccess access) { + super(access); + + DateRange referencePeriod = access.getReferencePeriod(); + DateRange [] analysisPeriods = access.getAnalysisPeriods(); + + if (referencePeriod == null) { + addProblem("fix.missing.reference.period"); + } + + if (analysisPeriods == null || analysisPeriods.length < 1) { + addProblem("fix.missing.analysis.periods"); + } + + if (!hasProblems()) { + this.referencePeriod = referencePeriod; + this.analysisPeriods = analysisPeriods; + } + } + + @Override + public CalculationResult innerCalculate( + FixingsOverview overview, + Function func + ) { + ColumnCache cc = new ColumnCache(); + + FitResult fitResult = doFitting(overview, cc, func); + + if (fitResult == null) { + return new CalculationResult(this); + } + + KMIndex<AnalysisPeriod []> analysisPeriods = + calculateAnalysisPeriods( + func, + fitResult.getParameters(), + overview, + cc); + + analysisPeriods.sort(); + + FixAnalysisResult far = new FixAnalysisResult( + fitResult.getParameters(), + fitResult.getReferenced(), + fitResult.getOutliers(), + analysisPeriods); + + return new CalculationResult(far, this); + } + + @Override + protected Filter createFilter() { + Filter ids = super.createFilter(); + DateRangeFilter rdf = new DateRangeFilter( + referencePeriod.getFrom(), + referencePeriod.getTo()); + return new AndFilter().add(rdf).add(ids); + } + + protected KMIndex<AnalysisPeriod []> calculateAnalysisPeriods( + Function function, + Parameters parameters, + FixingsOverview overview, + ColumnCache cc + ) { + Range range = new Range(from, to); + + int kmIndex = parameters.columnIndex("km"); + int maxQIndex = parameters.columnIndex("max_q"); + + double [] wq = new double[2]; + + int [] parameterIndices = + parameters.columnIndices(function.getParameterNames()); + + double [] parameterValues = new double[parameterIndices.length]; + + DateAverager dateAverager = new DateAverager(); + + KMIndex<AnalysisPeriod []> results = + new KMIndex<AnalysisPeriod []>(parameters.size()); + + IdsFilter idsFilter = new IdsFilter(events); + + TIntIntHashMap [] col2indices = + new TIntIntHashMap[analysisPeriods.length]; + + for (int i = 0; i < analysisPeriods.length; ++i) { + col2indices[i] = new TIntIntHashMap(); + } + + for (int row = 0, R = parameters.size(); row < R; ++row) { + double km = parameters.get(row, kmIndex); + parameters.get(row, parameterIndices, parameterValues); + + // This is the paraterized function for a given km. + de.intevation.flys.artifacts.math.Function instance = + function.instantiate(parameterValues); + + KmFilter kmFilter = new KmFilter(km); + + ArrayList<AnalysisPeriod> periodResults = + new ArrayList<AnalysisPeriod>(analysisPeriods.length); + + for (int ap = 0; ap < analysisPeriods.length; ++ap) { + DateRange analysisPeriod = analysisPeriods[ap]; + TIntIntHashMap col2index = col2indices[ap]; + + DateRangeFilter drf = new DateRangeFilter( + analysisPeriod.getFrom(), + analysisPeriod.getTo()); + + QWD [] qSectorAverages = new QWD[4]; + double [] qSectorStdDevs = new double[4]; + + ArrayList<QWD> allQWDs = new ArrayList<QWD>(); + + // for all Q sectors. + for (int qSector = qSectorStart; qSector < qSectorEnd; ++qSector) { + + Filter filter = new AndFilter() + .add(kmFilter) + .add(new SectorFilter(qSector)) + .add(drf) + .add(idsFilter); + + List<Fixing.Column> metas = overview.filter(range, filter); + + if (metas.isEmpty()) { + // No fixings for km and analysis period + continue; + } + + double sumQ = 0.0; + double sumW = 0.0; + + StandardDeviation stdDev = new StandardDeviation(); + + List<QWD> qwds = new ArrayList<QWD>(metas.size()); + + dateAverager.clear(); + + for (Fixing.Column meta: metas) { + if (meta.findQSector(km) != qSector) { + // Ignore not matching sectors. + continue; + } + + Column column = cc.getColumn(meta); + if (column == null || !column.getQW(km, wq)) { + continue; + } + + double fw = instance.value(wq[1]); + if (Double.isNaN(fw)) { + continue; + } + + double dw = (wq[0] - fw)*100.0; + + stdDev.increment(dw); + + Date date = column.getDate(); + String description = column.getDescription(); + + QWD qwd = new QWD( + wq[1], wq[0], + description, + date, true, + dw, getIndex(col2index, column.getIndex())); + + qwds.add(qwd); + + sumW += wq[0]; + sumQ += wq[1]; + + dateAverager.add(date); + } + + // Calulate average per Q sector. + int N = qwds.size(); + if (N > 0) { + allQWDs.addAll(qwds); + double avgW = sumW / N; + double avgQ = sumQ / N; + + double avgFw = instance.value(avgQ); + if (!Double.isNaN(avgFw)) { + double avgDw = (avgW - avgFw)*100.0; + Date avgDate = dateAverager.getAverage(); + + String avgDescription = "avg.deltawt." + qSector; + + QWD avgQWD = new QWD( + avgQ, avgW, avgDescription, avgDate, true, avgDw, 0); + + qSectorAverages[qSector] = avgQWD; + } + qSectorStdDevs[qSector] = stdDev.getResult(); + } + else { + qSectorStdDevs[qSector] = Double.NaN; + } + } // for all Q sectors + + QWD [] aqwds = allQWDs.toArray(new QWD[allQWDs.size()]); + + AnalysisPeriod periodResult = new AnalysisPeriod( + analysisPeriod, + aqwds, + qSectorAverages, + qSectorStdDevs); + periodResults.add(periodResult); + } + + double maxQ = -Double.MAX_VALUE; + for (AnalysisPeriod ap: periodResults) { + double q = ap.getMaxQ(); + if (q > maxQ) { + maxQ = q; + } + } + + double oldMaxQ = parameters.get(row, maxQIndex); + if (oldMaxQ < maxQ) { + parameters.set(row, maxQIndex, maxQ); + } + + results.add(km, periodResults.toArray( + new AnalysisPeriod[periodResults.size()])); + } + + return results; + } + + private static final int getIndex(TIntIntHashMap map, int colIdx) { + if (map.containsKey(colIdx)) { + return map.get(colIdx); + } + int index = map.size(); + map.put(colIdx, index); + return index; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,117 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.utils.KMIndex; + +import org.apache.log4j.Logger; + +/** + * Facet to show W values for Q values at km for a date. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixAnalysisEventsFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixAnalysisEventsFacet.class); + + /** Trivial Constructor. */ + public FixAnalysisEventsFacet() { + } + + + /** + * @param name + */ + public FixAnalysisEventsFacet(int index, String name, String description) { + super(index, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixAnalysisEventsFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry = + kmPeriods.binarySearch(currentKm); + + if(kmPeriodsEntry == null) { + logger.debug("getData: kmPeriodsEntry == null"); + return null; + } + + AnalysisPeriod[] periods = kmPeriodsEntry.getValue(); + if (periods == null) { + logger.debug("getData: periods == null"); + return null; + } + int ndx = index >> 8; + QWD[] qwdData = periods[ndx].getQWDs(); + if (qwdData == null) { + return null; + } + int ndy = index & 255; + for (int i = 0; i < qwdData.length; i++) { + if (qwdData[i].getIndex() == ndy) { + return qwdData[i]; + } + } + return null; + } + else { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixAnalysisEventsFacet deepCopy() { + FixAnalysisEventsFacet copy = new FixAnalysisEventsFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,113 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.utils.KMIndex; + +import org.apache.log4j.Logger; + +/** + * Facet to show W values for Q values at km for a date. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixAnalysisPeriodsFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixAnalysisPeriodsFacet.class); + + /** Trivial Constructor. */ + public FixAnalysisPeriodsFacet() { + } + + + /** + * @param name + */ + public FixAnalysisPeriodsFacet(int index, String name, String description) { + super(index, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixAnalysisPeriodsFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry = + kmPeriods.binarySearch(currentKm); + + if (kmPeriodsEntry == null) { + return null; + } + + AnalysisPeriod[] periods = kmPeriodsEntry.getValue(); + + if (periods == null) { + return null; + } + DateRange[] dates = new DateRange[periods.length]; + for (int i = 0; i < periods.length; i++) { + dates[i] = periods[i].getDateRange(); + } + return dates; + } + else { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixAnalysisPeriodsFacet deepCopy() { + FixAnalysisPeriodsFacet copy = new FixAnalysisPeriodsFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,77 @@ +package de.intevation.flys.artifacts.model.fixings; + +import java.util.Collection; +import java.util.Date; +import java.util.TreeSet; + +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.utils.KMIndex; + +public class FixAnalysisResult +extends FixResult +{ + protected KMIndex<AnalysisPeriod []> analysisPeriods; + + public FixAnalysisResult() { + } + + public FixAnalysisResult( + Parameters parameters, + KMIndex<QWD []> referenced, + KMIndex<QWI []> outliers, + KMIndex<AnalysisPeriod []> analysisPeriods + ) { + super(parameters, referenced, outliers); + this.analysisPeriods = analysisPeriods; + } + + public int getUsedSectorsInAnalysisPeriods() { + int result = 0; + for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) { + for (AnalysisPeriod period: entry.getValue()) { + for (int i = 0; i < 4; ++i) { + result |= period.getQSectorAverage(i) != null + ? (1 << i) + : 0; + } + // XXX: Stop early on result == ~(~0 << 4)) ? + } + } + return result; + } + + public Collection<Date> getReferenceEventsDates() { + TreeSet<Date> dates = new TreeSet<Date>(); + for (KMIndex.Entry<QWD []> entry: referenced) { + QWD [] values = entry.getValue(); + for (int i = 0; i < values.length; i++) { + dates.add(values[i].date); + } + } + return dates; + } + + public Collection<Date> getAnalysisEventsDates(int analysisPeriod) { + TreeSet<Date> dates = new TreeSet<Date>(); + for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) { + QWD [] qwds = entry.getValue()[analysisPeriod].getQWDs(); + if (qwds == null) { + continue; + } + for (int i = 0; i < qwds.length; i++) { + dates.add(qwds[i].date); + } + } + return dates; + } + + public KMIndex<AnalysisPeriod []> getAnalysisPeriods() { + return analysisPeriods; + } + + public void setAnalysisPeriods(KMIndex<AnalysisPeriod []> analysisPeriods) { + this.analysisPeriods = analysisPeriods; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,128 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.model.QWDDateRange; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.utils.KMIndex; + +import org.apache.log4j.Logger; + + +/** + * Facet to show average W values for Q sectors. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixAvSectorFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixAvSectorFacet.class); + + /** Trivial Constructor. */ + public FixAvSectorFacet() { + } + + + public FixAvSectorFacet(int ndx, String name, String description) { + super( + ndx, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext. + * + * @return the data as QWD array (QWD[]). + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixAvSectorFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry = + kmPeriods.binarySearch(currentKm); + + if (kmPeriodsEntry == null) { + logger.warn("No analysis periods found for km '" + currentKm + "'"); + return null; + } + + AnalysisPeriod[] periods = kmPeriodsEntry.getValue(); + + if (periods == null) { + logger.warn("No analysis periods specified!"); + return null; + } + + QWD[] qwdData = null; + int sectorNdx = index & 3; + int periodNdx = index >> 2; + + if (periodNdx < periods.length) { + qwdData = periods[periodNdx].getQSectorAverages(); + } + + if (logger.isDebugEnabled()) { + int resSize = qwdData != null ? qwdData.length : -1; + logger.debug("Found " + resSize + " result elements."); + } + + if (qwdData == null) { + return null; + } + return new QWDDateRange(qwdData[sectorNdx], periods[periodNdx].getDateRange()); + } + else { + logger.warn("Artifact is no instance of FLYSArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixAvSectorFacet deepCopy() { + FixAvSectorFacet copy = new FixAvSectorFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,419 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.common.utils.StringUtils; + +import de.intevation.flys.artifacts.access.FixAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.FixingsColumn; +import de.intevation.flys.artifacts.model.FixingsColumnFactory; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; +import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter; + +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.FixingsOverviewFactory; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.utils.DoubleUtil; +import de.intevation.flys.utils.KMIndex; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +public abstract class FixCalculation +extends Calculation +{ + private static Logger log = Logger.getLogger(FixCalculation.class); + + public static final double EPSILON = 1e-4; + + public static final String [] STANDARD_COLUMNS = { + "km", "chi_sqr", "max_q", "std-dev" + }; + + protected static class FitResult { + + protected Parameters parameters; + protected KMIndex<QWD []> referenced; + protected KMIndex<QWI []> outliers; + + public FitResult() { + } + + public FitResult( + Parameters parameters, + KMIndex<QWD []> referenced, + KMIndex<QWI []> outliers + ) { + this.parameters = parameters; + this.referenced = referenced; + this.outliers = outliers; + } + + public Parameters getParameters() { + return parameters; + } + + public KMIndex<QWD []> getReferenced() { + return referenced; + } + + public KMIndex<QWI []> getOutliers() { + return outliers; + } + } // class FitResult + + /** Helper class to bundle the meta information of a column + * and the real data. + */ + protected static class Column { + + protected Fixing.Column meta; + protected FixingsColumn data; + protected int index; + + public Column() { + } + + public Column(Fixing.Column meta, FixingsColumn data, int index) { + this.meta = meta; + this.data = data; + this.index = index; + } + + public Date getDate() { + return meta.getStartTime(); + } + + public String getDescription() { + return meta.getDescription(); + } + + public int getIndex() { + return index; + } + + public boolean getQW( + double km, + double [] qs, + double [] ws, + int index + ) { + qs[index] = data.getQ(km); + return data.getW(km, ws, index); + } + + public boolean getQW(double km, double [] wq) { + data.getW(km, wq, 0); + if (Double.isNaN(wq[0])) return false; + wq[1] = data.getQ(km); + return !Double.isNaN(wq[1]); + } + } // class Column + + /** + * Helper class to find the data belonging to meta info more quickly. + */ + protected static class ColumnCache { + + protected Map<Integer, Column> columns; + + public ColumnCache() { + columns = new HashMap<Integer, Column>(); + } + + public Column getColumn(Fixing.Column meta) { + Integer key = meta.getId(); + Column column = columns.get(key); + if (column == null) { + FixingsColumn data = FixingsColumnFactory + .getInstance() + .getColumnData(meta); + if (data != null) { + column = new Column(meta, data, columns.size()); + columns.put(key, column); + } + } + return column; + } + } // class ColumnCache + + + protected String river; + protected double from; + protected double to; + protected double step; + protected boolean preprocessing; + protected String function; + protected int [] events; + protected int qSectorStart; + protected int qSectorEnd; + + public FixCalculation() { + } + + public FixCalculation(FixAccess access) { + String river = access.getRiver(); + Double from = access.getFrom(); + Double to = access.getTo(); + Double step = access.getStep(); + String function = access.getFunction(); + int [] events = access.getEvents(); + Integer qSectorStart = access.getQSectorStart(); + Integer qSectorEnd = access.getQSectorEnd(); + Boolean preprocessing = access.getPreprocessing(); + + if (river == null) { + addProblem("fix.missing.river"); + } + + if (from == null) { + addProblem("fix.missing.from"); + } + + if (to == null) { + addProblem("fix.missing.to"); + } + + if (step == null) { + addProblem("fix.missing.step"); + } + + if (function == null) { + addProblem("fix.missing.function"); + } + + if (events == null || events.length < 1) { + addProblem("fix.missing.events"); + } + + if (qSectorStart == null) { + addProblem("fix.missing.qstart.sector"); + } + + if (qSectorEnd == null) { + addProblem("fix.missing.qend.sector"); + } + + if (preprocessing == null) { + addProblem("fix.missing.preprocessing"); + } + + if (!hasProblems()) { + this.river = river; + this.from = from; + this.to = to; + this.step = step; + this.function = function; + this.events = events; + this.qSectorStart = qSectorStart; + this.qSectorEnd = qSectorEnd; + this.preprocessing = preprocessing; + } + } + + protected static String toString( + String [] parameterNames, + double [] values + ) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parameterNames.length; ++i) { + if (i > 0) sb.append(", "); + sb.append(parameterNames[i]).append(": ").append(values[i]); + } + return sb.toString(); + } + + protected Filter createFilter() { + return new IdsFilter(events); + } + + protected List<Column> getEventColumns( + FixingsOverview overview, + ColumnCache cc + ) { + FixingsColumnFactory fcf = FixingsColumnFactory.getInstance(); + + Filter filter = createFilter(); + + List<Fixing.Column> metas = overview.filter(null, filter); + + List<Column> columns = new ArrayList<Column>(metas.size()); + + for (Fixing.Column meta: metas) { + + Column data = cc.getColumn(meta); + if (data == null) { + addProblem("fix.cannot.load.data"); + } + else { + columns.add(data); + } + } + + return columns; + } + + protected FitResult doFitting( + FixingsOverview overview, + ColumnCache cc, + Function func + ) { + boolean debug = log.isDebugEnabled(); + + final List<Column> eventColumns = getEventColumns(overview, cc); + + if (eventColumns.size() < 2) { + addProblem("fix.too.less.data.columns"); + return null; + } + + final double [] qs = new double[eventColumns.size()]; + final double [] ws = new double[qs.length]; + final boolean [] interpolated = new boolean[ws.length]; + + Fitting.QWDFactory qwdFactory = new Fitting.QWDFactory() { + @Override + public QWD create(double q, double w) { + // Check all the event columns for close match + // and take the description and the date from meta. + for (int i = 0; i < qs.length; ++i) { + if (Math.abs(qs[i]-q) < EPSILON + && Math.abs(ws[i]-w) < EPSILON) { + Column column = eventColumns.get(i); + return new QWD( + qs[i], ws[i], + column.getDescription(), + column.getDate(), + interpolated[i], + 0d, + column.getIndex()); + } + } + log.warn("cannot find column for (" + q + ", " + w + ")"); + return new QWD(q, w); + } + }; + + Fitting fitting = new Fitting(func, qwdFactory, preprocessing); + + String [] parameterNames = func.getParameterNames(); + + Parameters results = + new Parameters( + StringUtils.join(STANDARD_COLUMNS, parameterNames)); + + boolean invalid = false; + + double [] kms = DoubleUtil.explode(from, to, step / 1000.0); + + if (debug) { + log.debug("number of kms: " + kms.length); + } + + KMIndex<QWI []> outliers = new KMIndex<QWI []>(); + KMIndex<QWD []> referenced = new KMIndex<QWD []>(kms.length); + + int kmIndex = results.columnIndex("km"); + int chiSqrIndex = results.columnIndex("chi_sqr"); + int maxQIndex = results.columnIndex("max_q"); + int stdDevIndex = results.columnIndex("std-dev"); + int [] parameterIndices = results.columnIndices(parameterNames); + + int numFailed = 0; + + for (int i = 0; i < kms.length; ++i) { + double km = kms[i]; + + // Fill Qs and Ws from event columns. + for (int j = 0; j < ws.length; ++j) { + interpolated[j] = !eventColumns.get(j).getQW(km, qs, ws, j); + } + + fitting.reset(); + + if (!fitting.fit(qs, ws)) { + ++numFailed; + addProblem(km, "fix.fitting.failed"); + continue; + } + + referenced.add(km, fitting.referencedToArray()); + + if (fitting.hasOutliers()) { + outliers.add(km, fitting.outliersToArray()); + } + + int row = results.newRow(); + double [] values = fitting.getParameters(); + + results.set(row, kmIndex, km); + results.set(row, chiSqrIndex, fitting.getChiSquare()); + results.set(row, stdDevIndex, fitting.getStandardDeviation()); + results.set(row, maxQIndex, fitting.getMaxQ()); + invalid |= results.set(row, parameterIndices, values); + + if (debug) { + log.debug("km: "+km+" " + toString(parameterNames, values)); + } + } + + if (debug) { + log.debug("success: " + (kms.length - numFailed)); + log.debug("failed: " + numFailed); + } + + if (invalid) { + addProblem("fix.invalid.values"); + results.removeNaNs(); + } + + outliers.sort(); + referenced.sort(); + + return new FitResult( + results, + referenced, + outliers); + } + + public CalculationResult calculate() { + FixingsOverview overview = + FixingsOverviewFactory.getOverview(river); + + if (overview == null) { + addProblem("fix.no.overview.available"); + } + + Function func = FunctionFactory.getInstance() + .getFunction(function); + + if (func == null) { + addProblem("fix.invalid.function.name"); + } + + if (hasProblems()) { + return new CalculationResult(this); + } + + return innerCalculate(overview, func); + } + + protected abstract CalculationResult innerCalculate( + FixingsOverview overview, + Function function + ); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,121 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + + +/** + * Facet to show the W|Q values. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixDerivateFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixDerivateFacet.class); + + + /** Trivial Constructor. */ + public FixDerivateFacet() { + } + + + /** + * @param name + */ + public FixDerivateFacet(String name, String description) { + super(0, name, description, ComputeType.ADVANCE, null, null); + } + + public FixDerivateFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + + logger.debug("FixDerivateFacet.getData"); + if (!(artifact instanceof FLYSArtifact)) { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + String function = access.getFunction(); + Function ff = FunctionFactory.getInstance().getFunction(function); + Function.Derivative fd = ff.getDerivative(); + + Parameters params = result.getParameters(); + double maxQ = FixFacetUtils.getMaxQ(params, currentKm); + + String[] paramNames = ff.getParameterNames(); + + double[] coeffs = params.interpolate("km", currentKm, paramNames); + if (coeffs == null) { + logger.warn("getData: coeffs == null"); + return null; + } + + de.intevation.flys.artifacts.math.Function mf = + fd.instantiate(coeffs); + + FixFunction fix = new FixFunction( + "", + fd.getDescription(), + mf, + maxQ); + + return fix; + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixDerivateFacet deepCopy() { + FixDerivateFacet copy = new FixDerivateFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,104 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + + +/** + * Facet to show the W|Q values. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixDeviationFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixDeviationFacet.class); + + public static final String [] STD_DEV_COLUMN = { "std-dev" }; + + /** Trivial Constructor. */ + public FixDeviationFacet() { + } + + + /** + * @param name + */ + public FixDeviationFacet(String name, String description) { + super(0, name, description, ComputeType.ADVANCE, null, null); + } + + public FixDeviationFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixDeviationFacet.getData"); + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + Parameters params = result.getParameters(); + + double[] stdDev = + params.interpolate("km", currentKm, STD_DEV_COLUMN); + + if (stdDev == null) { + logger.warn("getData: stdDev == null at km " + currentKm); + return null; + } + + return stdDev; + } + else { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixDerivateFacet deepCopy() { + FixDerivateFacet copy = new FixDerivateFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,18 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.model.Parameters; + +public final class FixFacetUtils { + + public static final String [] MAX_Q_COLUMN = { "max_q" }; + + public static double getMaxQ(Parameters params, double km) { + double [] maxQ = params.interpolate("km", km, MAX_Q_COLUMN); + if (maxQ == null) { + return 1000d; + } + double mQ = Math.min(10000d, Math.abs(maxQ[0])); + return mQ + 0.05*mQ; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,40 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.math.Function; + +public class FixFunction +{ + protected String name; + protected String description; + protected Function function; + protected double maxQ; + + public FixFunction ( + String name, + String description, + Function function, + double maxQ + ) { + this.name = name; + this.description = description; + this.function = function; + this.maxQ = maxQ; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Function getFunction() { + return function; + } + + public double getMaxQ() { + return maxQ; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,108 @@ +package de.intevation.flys.artifacts.model.fixings; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.KMIndex; + +/** + * Facet to show average W values for Q sectors. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixLongitudinalAnalysisFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixLongitudinalAnalysisFacet.class); + + /** Trivial Constructor. */ + public FixLongitudinalAnalysisFacet() { + } + + + public FixLongitudinalAnalysisFacet( + int ndx, + String name, + String description) + { + super( + ndx, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext. + * + * @return the data as KMIndex. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixLongitudinalAnalysisFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + if (kmPeriods == null) { + logger.warn("No analysis periods found."); + return null; + } + int periodNdx = index >> 8; + int qwdNdx = index & 255; + KMIndex<QWD> resPeriods = + new KMIndex<QWD>(); + for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) { + AnalysisPeriod ap = entry.getValue()[periodNdx]; + QWD[] qwds = ap.qwds; + for(int i = 0; i < qwds.length; i++) { + if(qwds[i].getIndex() == qwdNdx) { + resPeriods.add(entry.getKm(), qwds[i]); + } + } + } + + + return resPeriods; + } + else { + logger.warn("Artifact is no instance of FLYSArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixLongitudinalAnalysisFacet deepCopy() { + FixLongitudinalAnalysisFacet copy = new FixLongitudinalAnalysisFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAvSectorFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.flys.artifacts.model.fixings; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.KMIndex; + +public class FixLongitudinalAvSectorFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = + Logger.getLogger(FixLongitudinalAvSectorFacet.class); + + /** Trivial Constructor. */ + public FixLongitudinalAvSectorFacet() { + } + + + public FixLongitudinalAvSectorFacet( + int ndx, + String name, + String description) + { + super( + ndx, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext. + * + * @return the data as KMIndex. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixLongitudinalAvSectorFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + if (kmPeriods == null) { + logger.warn("No analysis periods found."); + return null; + } + int periodNdx = index >> 2; + KMIndex<AnalysisPeriod> resPeriods = + new KMIndex<AnalysisPeriod>(); + for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) { + AnalysisPeriod ap = entry.getValue()[periodNdx]; + resPeriods.add(entry.getKm(), ap); + } + + return resPeriods; + } + else { + logger.warn("Artifact is no instance of FLYSArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixLongitudinalAvSectorFacet deepCopy() { + FixLongitudinalAvSectorFacet copy = new FixLongitudinalAvSectorFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,118 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.utils.KMIndex; + +import org.apache.log4j.Logger; + +/** + * Facet to show average W values for Q sectors. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixLongitudinalDeviationFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixLongitudinalDeviationFacet.class); + + /** Trivial Constructor. */ + public FixLongitudinalDeviationFacet() { + } + + + public FixLongitudinalDeviationFacet( + int ndx, + String name, + String description) + { + super( + ndx, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext. + * + * @return the data as KMIndex. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixLongitudinalDeviationFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + + KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods(); + + if (kmPeriods == null) { + logger.warn("No analysis periods found."); + return null; + } + + Parameters params = result.getParameters(); + + KMIndex<double[]> kmIndex = new KMIndex<double[]>(); + for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) { + double km = entry.getKm(); + double[] stdDev = + params.interpolate("km", km, new String[] {"std-dev"}); + + if(stdDev == null) { + logger.warn("getData: stdDev == null"); + continue; + } + kmIndex.add(km, stdDev); + } + + return kmIndex; + } + else { + logger.warn("Artifact is no instance of FLYSArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixLongitudinalDeviationFacet deepCopy() { + FixLongitudinalDeviationFacet copy = new FixLongitudinalDeviationFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,115 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import de.intevation.flys.utils.KMIndex; + +import org.apache.log4j.Logger; + + +/** + * Facet to show average W values for Q sectors. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixLongitudinalReferenceFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixLongitudinalReferenceFacet.class); + + /** Trivial Constructor. */ + public FixLongitudinalReferenceFacet() { + } + + + public FixLongitudinalReferenceFacet( + int ndx, + String name, + String description) + { + super( + ndx, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext. + * + * @return the data as KMIndex. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixLongitudinalReferenceFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + + KMIndex<QWD []> kmReference = result.getReferenced(); + + if (kmReference == null) { + logger.warn("No references found."); + return null; + } + + int qwdNdx = index & 255; + KMIndex<QWD> resReference = + new KMIndex<QWD>(); + for (KMIndex.Entry<QWD[]> entry: kmReference) { + QWD[] qwds = entry.getValue(); + for(int i = 0; i < qwds.length; i++) { + if(qwds[i].getIndex() == qwdNdx) { + resReference.add(entry.getKm(), qwds[i]); + } + } + } + return resReference; + } + else { + logger.warn("Artifact is no instance of FLYSArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixLongitudinalReferenceFacet deepCopy() { + FixLongitudinalReferenceFacet copy = + new FixLongitudinalReferenceFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,103 @@ +package de.intevation.flys.artifacts.model.fixings; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.KMIndex; + +/** + * Facet to show the outliers in a fix calculation. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixOutlierFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixOutlierFacet.class); + + /** Trivial Constructor. */ + public FixOutlierFacet() { + } + + + /** + * @param name + */ + public FixOutlierFacet(String name, String description) { + super(0, name, description, ComputeType.ADVANCE, null, null); + } + + public FixOutlierFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact; needs to be a FLYSArtifact. + * @param context the CallContext; required to retrieve the value of + * <i>currentKm</i>. + * + * @return an array of QW objects or null. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixOutlierFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixResult result = (FixResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + KMIndex<QWI []> kmQWs = result.getOutliers(); + KMIndex.Entry<QWI []> qwsEntry = kmQWs.binarySearch(currentKm); + + QWI [] qws = null; + if (qwsEntry != null) { + qws = qwsEntry.getValue(); + + if (logger.isDebugEnabled()) { + logger.debug("Found " + (qws != null ? qws.length : 0) + + " KMIndex.Entry for km " + currentKm); + } + } + else { + logger.debug("Found no KMIndex.Entry for km " + currentKm); + } + + return qws; + } + + logger.warn("Not an instance of FLYSArtifact."); + return null; + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixOutlierFacet deepCopy() { + FixOutlierFacet copy = new FixOutlierFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.access.FixRealizingAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.artifacts.model.Segment; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.model.River; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class FixRealizingCalculation +extends FixCalculation +{ + private static Logger log = + Logger.getLogger(FixRealizingCalculation.class); + + protected boolean isQ; + protected List<Segment> segments; + + public FixRealizingCalculation() { + } + + public FixRealizingCalculation(FixRealizingAccess access) { + super(access); + + Boolean isQ = access.isQ(); + List<Segment> segments = access.getSegments(); + + if (isQ == null) { + // TODO: i18n + addProblem("fix.realize.missing.is.q"); + } + + if (segments == null || segments.isEmpty()) { + // TODO: i18n + addProblem("fix.realize.missing.segments"); + } + + River r = RiverFactory.getRiver(river); + + if (r == null) { + // TODO: i18n + addProblem("fix.no.such.river"); + } + + if (!hasProblems()) { + this.isQ = isQ; + this.segments = segments; + + // Convert from W to Q + Segment.setReferencePointConvertQ(segments, r, isQ, this); + } + } + + @Override + protected CalculationResult innerCalculate( + FixingsOverview overview, + Function func + ) { + ColumnCache cc = new ColumnCache(); + FitResult fitResult = doFitting(overview, cc, func); + + if (fitResult == null) { + return new CalculationResult(this); + } + + Segment segment = segments.get(0); + int numResults = segment.numValues(); + + WQKms [] results = new WQKms[numResults]; + for (int i = 0; i < results.length; ++i) { + results[i] = new WQKms(); + } + + Parameters parameters = fitResult.getParameters(); + + int kmIndex = parameters.columnIndex("km"); + int [] parameterIndices = + parameters.columnIndices(func.getParameterNames()); + + double [] parameterValues = new double[parameterIndices.length]; + + for (int row = 0, R = parameters.size(); row < R; ++row) { + double km = parameters.get(row, kmIndex); + + if (!segment.inside(km)) { + Segment nextSeg = null; + for (Segment seg: segments) { + if (seg.inside(km)) { + nextSeg = seg; + break; + } + } + if (nextSeg == null) { + // TODO: i18n + addProblem(km, "fix.cannot.find.segment"); + continue; + } + segment = nextSeg; + } + + parameters.get(row, parameterIndices, parameterValues); + + de.intevation.flys.artifacts.math.Function instance = + func.instantiate(parameterValues); + + double [] values = segment.getValues(); + for (int i = 0; i < numResults; ++i) { + double q = values[i]; + double w = instance.value(q); + + if (Double.isNaN(w)) { + // TODO: i18n + addProblem(km, "fix.cannot.calculate.function", q); + } + else { + results[i].add(w, q, km); + } + } + } + + // name the curves + for (int i = 0; i < results.length; ++i) { + results[i].setName(createName(i)); + } + + FixRealizingResult frr = new FixRealizingResult( + parameters, + fitResult.getReferenced(), + fitResult.getOutliers(), + results); + + return new CalculationResult(frr, this); + } + + protected String createName(int index) { + // TODO: i18n + StringBuilder sb = new StringBuilder(isQ ? "Q" : "W"); + sb.append(" benutzerdefiniert ("); + for (int i = 0, N = segments.size(); i < N; ++i) { + if (i > 0) { + sb.append("; "); + } + Segment segment = segments.get(i); + double [] backup = segment.getBackup(); + double [] values = segment.getValues(); + sb.append((backup != null ? backup : values)[index]); + } + sb.append(')'); + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,35 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.utils.KMIndex; + +public class FixRealizingResult +extends FixResult +{ + public WQKms [] wqkms; + + public FixRealizingResult() { + } + + public FixRealizingResult( + Parameters parameters, + KMIndex<QWD []> referenced, + KMIndex<QWI []> outliers, + WQKms [] wqkms + ) { + super(parameters, referenced, outliers); + this.wqkms = wqkms; + } + + public WQKms [] getWQKms() { + return wqkms; + } + + public void setWQKms(WQKms [] wqkms) { + this.wqkms = wqkms; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,102 @@ +package de.intevation.flys.artifacts.model.fixings; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.KMIndex; + + +/** + * Facet to show W values for Q values at km for a date. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixReferenceEventsFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixReferenceEventsFacet.class); + + /** Trivial Constructor. */ + public FixReferenceEventsFacet() { + } + + + /** + * @param name + */ + public FixReferenceEventsFacet(int index, String name, String description) { + super(index, + name, + description, + ComputeType.ADVANCE, + null, + null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixReferenceEventsFacet.getData"); + + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixResult result = (FixResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + KMIndex<QWD []> kmQWs = result.getReferenced(); + KMIndex.Entry<QWD []> kmQWsEntry = kmQWs.binarySearch(currentKm); + QWD[] qwds = null; + if (kmQWsEntry != null) { + int ndx = index & 255; + qwds = kmQWsEntry.getValue(); + for (int i = 0; i < qwds.length; i++) { + if (qwds[i].getIndex() == ndx) { + return qwds[i]; + } + } + return null; + } + return null; + } + else { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + } + + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixReferenceEventsFacet deepCopy() { + FixReferenceEventsFacet copy = new FixReferenceEventsFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,53 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.utils.KMIndex; + +import java.io.Serializable; + +public class FixResult +implements Serializable +{ + protected Parameters parameters; + protected KMIndex<QWD []> referenced; + protected KMIndex<QWI []> outliers; + + public FixResult() { + } + + public FixResult( + Parameters parameters, + KMIndex<QWD []> referenced, + KMIndex<QWI []> outliers + ) { + this.parameters = parameters; + this.referenced = referenced; + this.outliers = outliers; + } + + public KMIndex<QWD []> getReferenced() { + return referenced; + } + + public void setReferenced(KMIndex<QWD []> referenced) { + this.referenced = referenced; + } + + public KMIndex<QWI []> getOutliers() { + return outliers; + } + + public void setOutliers(KMIndex<QWI []> outliers) { + this.outliers = outliers; + } + + public Parameters getParameters() { + return parameters; + } + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,126 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAnalysisAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +/** + * Facet to show the W|Q values. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixWQCurveFacet +extends DataFacet +implements FacetTypes { + + /** House logger. */ + private static Logger logger = Logger.getLogger(FixWQCurveFacet.class); + + /** Trivial Constructor. */ + public FixWQCurveFacet() { + } + + + /** + * @param description Description of the facet. + */ + public FixWQCurveFacet(String description) { + super(0, FIX_WQ_CURVE, description, ComputeType.ADVANCE, null, null); + } + + public FixWQCurveFacet(int index, String description) { + super(index, FIX_WQ_CURVE, description, ComputeType.ADVANCE, null, null); + } + + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("FixWQCurveFacet.getData"); + if (artifact instanceof FLYSArtifact) { + FLYSArtifact flys = (FLYSArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixResult result = (FixResult) res.getData(); + double currentKm = + ((Double)context.getContextValue("currentKm")).doubleValue(); + + logger.debug("getData: km = " + currentKm); + + String function = access.getFunction(); + Function ff = FunctionFactory.getInstance().getFunction(function); + + if (ff == null) { + logger.warn("getData: ff == null"); + return null; + } + + Parameters params = result.getParameters(); + String[] paramNames = ff.getParameterNames(); + + double [] coeffs = params.interpolate("km", currentKm, paramNames); + + if (coeffs == null) { + logger.warn("getData: coeffs == null"); + return null; + } + + de.intevation.flys.artifacts.math.Function mf = + ff.instantiate(coeffs); + + double maxQ = FixFacetUtils.getMaxQ(params, currentKm); + logger.debug("getData: maxQ = " + maxQ); + + FixFunction fix = new FixFunction( + ff.getName(), + ff.getDescription(), + mf, + maxQ); + + return fix; + } + else { + logger.debug("Not an instance of FixationArtifact."); + return null; + } + } + + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public FixWQCurveFacet deepCopy() { + FixWQCurveFacet copy = new FixWQCurveFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixWaterlevelFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,49 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WaterlevelFacet; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +public class FixWaterlevelFacet +extends WaterlevelFacet +{ + public FixWaterlevelFacet() { + } + + public FixWaterlevelFacet(int index, String name, String description) { + super(index, name, description, ComputeType.ADVANCE, null, null); + } + + public FixWaterlevelFacet( + int index, + String name, + String description, + ComputeType type, + String stateID, + String hash + ) { + super(index, name, description, type, hash, stateID); + } + + @Override + protected WQKms [] getWQKms(CalculationResult res) { + FixRealizingResult fr = (FixRealizingResult)res.getData(); + return fr != null ? fr.getWQKms() : null; + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + FixWaterlevelFacet copy = new FixWaterlevelFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,38 @@ +package de.intevation.flys.artifacts.model.fixings; + +import java.util.Date; + +public class QWD +extends QWI +{ + protected double deltaW; + + public QWD() { + } + + public QWD(double q, double w) { + super(q, w); + } + + public QWD( + double q, + double w, + String description, + Date date, + boolean interpolated, + double deltaW, + int index + ) { + super(q, w, description, date, interpolated, index); + this.deltaW = deltaW; + } + + public double getDeltaW() { + return deltaW; + } + + public void setDeltaW(double deltaW) { + this.deltaW = deltaW; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/QWI.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,69 @@ +package de.intevation.flys.artifacts.model.fixings; + +import de.intevation.flys.artifacts.model.QW; + +import java.util.Date; + +public class QWI +extends QW +{ + protected String description; + protected Date date; + protected boolean interpolated; + protected int index; + + public QWI() { + } + + public QWI(double q, double w) { + super(q, w); + } + + public QWI( + double q, + double w, + String description, + Date date, + boolean interpolated, + int index + ) { + super(q, w); + this.description = description; + this.date = date; + this.interpolated = interpolated; + this.index = index; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean getInterpolated() { + return interpolated; + } + + public void setInterpolated(boolean interpolated) { + this.interpolated = interpolated; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WMSDBLayerFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,106 @@ +package de.intevation.flys.artifacts.model.map; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +public class WMSDBLayerFacet extends WMSLayerFacet { + + protected String data; + protected String filter; + protected String labelItem; + protected String geometryType; + protected String connection; + protected String connectionType; + + + public WMSDBLayerFacet() { + super(); + } + + + public WMSDBLayerFacet(int index, String name, String description) { + this(index, name, description, ComputeType.FEED, null, null); + } + + + public WMSDBLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash + + ) { + super(index, name, description, type, stateId, hash); + } + + + public WMSDBLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash, + String url + ) { + super(index, name, description, type, stateId, hash, url); + } + + + public void setFilter(String filter) { + this.filter = filter; + } + + public String getFilter() { + return filter; + } + + public void setData(String data) { + this.data = data; + } + + public String getData() { + return data; + } + + public void setGeometryType(String geometryType) { + this.geometryType = geometryType; + } + + public String getGeometryType() { + return geometryType; + } + + public void setConnection(String connection) { + this.connection = connection; + } + + public String getConnection() { + return connection; + } + + public void setConnectionType(String connectionType) { + this.connectionType = connectionType; + } + + public String getConnectionType() { + return connectionType; + } + + public void setLabelItem(String labelItem) { + this.labelItem = labelItem; + } + + public String getLabelItem() { + return labelItem; + } + + + @Override + public boolean isQueryable() { + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WMSLayerFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,173 @@ +package de.intevation.flys.artifacts.model.map; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifactdatabase.state.DefaultFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.utils.GeometryUtils; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +public class WMSLayerFacet +extends DefaultFacet +{ + protected ComputeType type; + protected List<String> layers; + protected String stateId; + protected String hash; + protected String url; + protected Envelope extent; + protected String srid; + + + private static final Logger logger = Logger.getLogger(WMSLayerFacet.class); + + public WMSLayerFacet() { + } + + + public WMSLayerFacet(int index, String name, String description) { + this(index, name, description, ComputeType.FEED, null, null); + } + + + public WMSLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash + + ) { + super(index, name, description); + this.layers = new ArrayList<String>(); + this.type = type; + this.stateId = stateId; + this.hash = hash; + } + + + public WMSLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash, + String url + ) { + this(index, name, description, type, stateId, hash); + this.url = url; + } + + + public void addLayer(String name) { + if (name != null && name.length() > 0) { + layers.add(name); + } + } + + + public List<String> getLayers() { + return layers; + } + + + public void removeLayer(String layer) { + if (layers != null) { + layers.remove(layer); + } + } + + + public void setExtent(Envelope extent) { + if (extent != null) { + this.extent = extent; + } + else { + logger.debug("setExtent(): extent is null"); + } + } + + + public Envelope getExtent() { + return extent; + } + + + public void setSrid(String srid) { + if (srid != null) { + this.srid = srid; + } + } + + + public String getSrid() { + return srid; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + return null; + } + + + @Override + public Node toXML(Document doc) { + ElementCreator ec = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element facet = ec.create("facet"); + ec.addAttr(facet, "description", description, true); + ec.addAttr(facet, "index", String.valueOf(index), true); + ec.addAttr(facet, "name", name, true); + ec.addAttr(facet, "url", url, true); + ec.addAttr(facet, "layers", layers.get(0), true); + ec.addAttr(facet, "srid", srid != null ? srid : "", true); + ec.addAttr(facet, "extent", extent != null + ? GeometryUtils.jtsBoundsToOLBounds(extent) + : "", true); + ec.addAttr(facet, "queryable", String.valueOf(isQueryable()), true); + + return facet; + } + + + public boolean isQueryable() { + return false; + } + + + @Override + public Facet deepCopy() { + WMSLayerFacet copy = new WMSLayerFacet(); + copy.set(this); + + copy.type = type; + copy.layers = new ArrayList<String>(layers); + copy.stateId = stateId; + copy.hash = hash; + copy.url = url; + copy.extent = extent; + copy.srid = srid; + + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,83 @@ +package de.intevation.flys.artifacts.model.map; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.model.Calculation; + + +public class WSPLGENCalculation extends Calculation { + + private static final Logger log = Logger.getLogger(WSPLGENCalculation.class); + + protected Map<Integer, String> errors; + protected Map<Integer, String> warnings; + + + public WSPLGENCalculation() { + errors = new HashMap<Integer, String>(); + warnings = new HashMap<Integer, String>(); + } + + + public void addError(Integer key, String msg) { + log.debug("New error: (" + key + ") " + msg); + errors.put(key, msg); + } + + + public void addWarning(Integer key, String msg) { + log.debug("New warning: (" + key + ") " + msg); + warnings.put(key, msg); + } + + + public int numErrors() { + return errors.size(); + } + + + public int numWarnings() { + return warnings.size(); + } + + + @Override + public void toXML(Document document, CallMeta meta) { + Element root = document.createElement("problems"); + + if (numErrors() > 0) { + Set<Map.Entry<Integer, String>> entrySet = errors.entrySet(); + + for (Map.Entry<Integer, String> entry: entrySet) { + Element problem = document.createElement("problem"); + problem.setAttribute("error", String.valueOf(entry.getKey())); + problem.setTextContent(entry.getValue()); + + root.appendChild(problem); + } + } + + if (numWarnings() > 0) { + Set<Map.Entry<Integer, String>> entrySet = warnings.entrySet(); + + for (Map.Entry<Integer, String> entry: entrySet) { + Element problem = document.createElement("problem"); + problem.setAttribute("error", String.valueOf(entry.getKey())); + problem.setTextContent(entry.getValue()); + + root.appendChild(problem); + } + } + + document.appendChild(root); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENJob.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,473 @@ +package de.intevation.flys.artifacts.model.map; + +import java.io.IOException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.wsplgen.FacetCreator; + + +public class WSPLGENJob { + + public static final String GEL_SPERRE = "SPERRE"; + public static final String GEL_NOSPERRE = "NOSPERRE"; + + + protected FLYSArtifact artifact; + + protected CallContext callContext; + + protected WSPLGENCalculation calculation; + + protected FacetCreator facetCreator; + + protected File workingDir; + + protected String dgm; + protected String pro; + protected String wsp; + protected String wspTag; + protected String axis; + protected String area; + protected String gel; + protected String outFile; + + protected List<String> lin; + + protected int out; + + protected double start; + protected double end; + protected double from; + protected double to; + protected double diff; + protected double dist; + + + + public WSPLGENJob( + FLYSArtifact flys, + File workingDir, + FacetCreator facetCreator, + CallContext context, + WSPLGENCalculation calculation) + { + this.artifact = flys; + this.workingDir = workingDir; + this.facetCreator = facetCreator; + this.callContext = context; + this.calculation = calculation; + + out = -1; + start = Double.NaN; + end = Double.NaN; + from = Double.NaN; + to = Double.NaN; + diff = Double.NaN; + dist = Double.NaN; + lin = new ArrayList<String>(3); + } + + + public File getWorkingDir() { + return workingDir; + } + + + public FLYSArtifact getArtifact() { + return artifact; + } + + + public FacetCreator getFacetCreator() { + return facetCreator; + } + + + public WSPLGENCalculation getCalculation() { + return calculation; + } + + + public CallContext getCallContext() { + return callContext; + } + + + public void setWsp(String wsp) { + this.wsp = wsp; + } + + + public String getWsp() { + return wsp; + } + + + public void setWspTag(String wspTag) { + this.wspTag = wspTag; + } + + + public String getWspTag() { + return wspTag; + } + + + public void addLin(String lin) { + this.lin.add(lin); + } + + + public List<String> getLin() { + return lin; + } + + + public void setAxis(String axis) { + this.axis = axis; + } + + + public String getAxis() { + return axis; + } + + + public void setArea(String area) { + this.area = area; + } + + + public String getArea() { + return area; + } + + + public void setOut(int out) { + this.out = out; + } + + + public int getOut() { + return out; + } + + + public void setOutFile(String outFile) { + this.outFile = outFile; + } + + + public String getOutFile() { + return outFile; + } + + + public void setStart(double start) { + this.start = start; + } + + + public double getStart() { + return start; + } + + + public void setEnd(double end) { + this.end = end; + } + + + public double getEnd() { + return end; + } + + + public void setPro(String pro) { + this.pro = pro; + } + + + public String getPro() { + return pro; + } + + + public void setDgm(String dgm) { + this.dgm = dgm; + } + + + public String getDgm() { + return dgm; + } + + + public void setFrom(double from) { + this.from = from; + } + + + public double getFrom() { + return from; + } + + + public void setTo(double to) { + this.to = to; + } + + + public double getTo() { + return to; + } + + + public void setDiff(double diff) { + this.diff = diff; + } + + + public double getDiff() { + return diff; + } + + + public void setDist(double dist) { + this.dist = dist; + } + + + public double getDist() { + return dist; + } + + + public void setGel(String gel) { + if (gel == null || gel.length() == 0) { + return; + } + + if (gel.equals(GEL_SPERRE) || gel.equals(GEL_NOSPERRE)) { + this.gel = gel; + } + } + + + public String getGel() { + return gel; + } + + + public void toFile(File file) + throws IOException, IllegalArgumentException + { + PrintWriter writer = null; + + try { + writer = + new PrintWriter( + new OutputStreamWriter( + new FileOutputStream(file))); + + write(writer); + } + finally { + if (writer != null) { + writer.flush(); + writer.close(); + } + } + } + + + protected void write(PrintWriter writer) + throws IOException, IllegalArgumentException + { + writeWsp(writer); // required + writeWspTag(writer); // required + writeLin(writer); + writeAxis(writer); + writeArea(writer); + writeOut(writer); + writeOutFile(writer); + writeRange(writer); + writeDelta(writer); + writeGel(writer); + writeDist(writer); + writePro(writer); + writeDgm(writer); // required + } + + + protected void writeWsp(PrintWriter writer) + throws IllegalArgumentException + { + String wsp = getWsp(); + + if (wsp != null && wsp.length() > 0) { + writer.println("-WSP=\"" + wsp + "\""); + return; + } + + throw new IllegalArgumentException("Required WSP missing!"); + } + + protected void writeWspTag(PrintWriter writer) + throws IllegalArgumentException + { + String wspTag = getWspTag(); + + if (wspTag != null && wspTag.length() > 0) { + writer.println("-WSPTAG=\"" + wspTag + "\""); + return; + } + + throw new IllegalArgumentException("Required WSPTAG missing!"); + } + + protected void writeLin(PrintWriter writer) + throws IllegalArgumentException + { + List<String> lins = getLin(); + + if (lins != null && !lins.isEmpty()) { + for (String lin: lins) { + writer.println("-LIN=\"" + lin + "\""); + } + } + } + + protected void writeAxis(PrintWriter writer) + throws IllegalArgumentException + { + String axis = getAxis(); + + if (axis != null && axis.length() > 0) { + writer.println("-ACHSE=\"" + axis + "\""); + } + } + + protected void writeGel(PrintWriter writer) + throws IllegalArgumentException + { + if (area != null && area.length() > 0) { + writer.println("-GEL=" + getGel()); + } + } + + protected void writeArea(PrintWriter writer) + throws IllegalArgumentException + { + String area = getArea(); + + if (area != null && area.length() > 0) { + writer.println("-GEBIET=\"" + area + "\""); + } + } + + + protected void writeOut(PrintWriter writer) + throws IllegalArgumentException + { + int out = getOut(); + + if (out >= 0) { + writer.println("-OUTPUT=" + String.valueOf(out)); + } + } + + protected void writeOutFile(PrintWriter writer) + throws IllegalArgumentException + { + String outFile = getOutFile(); + + if (outFile != null && outFile.length() > 0) { + writer.println("-AUSGABE=\""+ outFile + "\""); + } + } + + protected void writeRange(PrintWriter writer) + throws IllegalArgumentException + { + StringBuilder sb = new StringBuilder("-STRECKE="); + + double start = getStart(); + double end = getEnd(); + + if (Double.isNaN(start) && Double.isNaN(end)) { + return; + } + + if (! Double.isNaN(getStart())) { + sb.append(getStart()); + } + + sb.append(","); + + if (! Double.isNaN(getEnd())) { + sb.append(getEnd()); + } + + writer.println(sb.toString()); + } + + protected void writeDelta(PrintWriter writer) + throws IllegalArgumentException + { + StringBuilder sb = new StringBuilder("-DELTA="); + if (! Double.isNaN(from)) { + sb.append(from); + } + + sb.append(","); + + if (! Double.isNaN(to)) { + sb.append(to); + } + + sb.append(","); + + if (! Double.isNaN(diff)) { + sb.append(diff); + } + + writer.println(sb.toString()); + } + + protected void writeDist(PrintWriter writer) + throws IllegalArgumentException + { + if (! Double.isNaN(getDist())) { + writer.println("-DIST=" + String.valueOf(getDist())); + } + } + + protected void writePro(PrintWriter writer) + throws IllegalArgumentException + { + if (pro != null && pro.length() > 0) { + writer.println("-PRO=\"" + getPro() + "\""); + } + } + + protected void writeDgm(PrintWriter writer) + throws IllegalArgumentException + { + if (dgm != null && dgm.length() > 0) { + writer.println("-DGM=\"" + getDgm() + "\""); + return; + } + + throw new IllegalArgumentException("Required DGM missing!"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENLayerFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,46 @@ +package de.intevation.flys.artifacts.model.map; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +public class WSPLGENLayerFacet +extends WMSLayerFacet +{ + public WSPLGENLayerFacet() { + } + + + public WSPLGENLayerFacet(int index, String name, String description) { + this(index, name, description, ComputeType.FEED, null, null); + } + + + public WSPLGENLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash + ) { + super(index, name, description, type, stateId, hash); + } + + public WSPLGENLayerFacet( + int index, + String name, + String description, + ComputeType type, + String stateId, + String hash, + String url + ) { + super(index, name, description, type, stateId, hash, url); + } + + + @Override + public boolean isQueryable() { + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENReportFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,58 @@ +package de.intevation.flys.artifacts.model.map; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * This facet is used to provide WSPLGEN reports <b>only</b>. + */ +public class WSPLGENReportFacet extends ReportFacet { + + private static Logger logger = Logger.getLogger(WSPLGENReportFacet.class); + + + protected CalculationResult result; + + + public WSPLGENReportFacet() { + } + + + public WSPLGENReportFacet( + ComputeType type, + String hash, + String stateId, + CalculationResult result + ) { + super(type, hash, stateId); + this.result = result; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + return result.getReport(); + } + + + @Override + public Facet deepCopy() { + WSPLGENReportFacet copy = new WSPLGENReportFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + copy.result = result; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,60 @@ +package de.intevation.flys.artifacts.model.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet for serving bed density data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedDensityFacet extends DataFacet { + + private static final long serialVersionUID = 1L; + + private static Logger logger = Logger.getLogger(BedDensityFacet.class); + + public BedDensityFacet() { + } + + public BedDensityFacet(int idx, String name, String description, + ComputeType type, String stateId, String hash) { + super(idx, name, description, type, hash, stateId); + } + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for bed density at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute(context, hash, + stateId, type, false); + + int ndx = index >> 8; + Object[] data = + ((BedQualityResult[]) res.getData())[ndx].getParameters(); // TODO CAST TO SPECIFIC CLASS + + int ndy = index & 255; + return data != null && data.length > ndy ? data[ndy] : null; + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + BedDensityFacet copy = new BedDensityFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,59 @@ +package de.intevation.flys.artifacts.model.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet for serving bed diameter data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedDiameterFacet extends DataFacet { + + private static final long serialVersionUID = 1L; + + private static Logger logger = Logger.getLogger(BedDiameterFacet.class); + + public BedDiameterFacet() { + } + + public BedDiameterFacet(int idx, String name, String description, + ComputeType type, String stateId, String hash) { + super(idx, name, description, type, hash, stateId); + } + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for bed diameter at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute(context, hash, + stateId, type, false); + + int ndx = index >> 8; + Object[] data = ((BedQualityResult[]) res.getData())[ndx].getBedResults(); // TODO CAST TO SPECIFIC CLASS + + int ndy = index & 255; + return data != null && data.length > ndy ? data[ndy] : null; + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + BedDiameterFacet copy = new BedDiameterFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,64 @@ +package de.intevation.flys.artifacts.model.minfo; + +import gnu.trove.TDoubleArrayList; + + +public class BedDiameterResult +extends BedQualityDiameterResult +{ + protected TDoubleArrayList diameterCap; + protected TDoubleArrayList diameterSub; + + public BedDiameterResult ( + String type, + TDoubleArrayList diameterCap, + TDoubleArrayList diameterSub, + TDoubleArrayList km + ) { + super(type, km); + this.diameterCap = diameterCap; + this.diameterSub = diameterSub; + } + + public double getDiameterCap(int ndx) { + if (diameterCap != null) { + return this.diameterCap.get(ndx); + } + return Double.NaN; + } + + public double getDiameterSub(int ndx) { + if (diameterSub != null) { + return this.diameterSub.get(ndx); + } + return Double.NaN; + } + + public double getDiameterCap(double km) { + if (kms.indexOf(km) >= 0) { + return diameterCap.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double getDiameterSub(double km) { + if (kms.indexOf(km) >= 0) { + return diameterSub.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double[][] getDiameterCapData() { + return new double[][] { + kms.toNativeArray(), + diameterCap.toNativeArray() + }; + } + + public double[][] getDiameterSubData() { + return new double[][] { + kms.toNativeArray(), + diameterSub.toNativeArray() + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,103 @@ +package de.intevation.flys.artifacts.model.minfo; + +import org.apache.log4j.Logger; + +import gnu.trove.TDoubleArrayList; +import de.intevation.flys.artifacts.model.NamedObjectImpl; + +public class BedHeight +extends NamedObjectImpl +{ + private static Logger log = Logger.getLogger(BedHeight.class); + + protected TDoubleArrayList heights; + protected TDoubleArrayList station; + protected TDoubleArrayList data_gap; + + public BedHeight() { + heights = new TDoubleArrayList(); + station = new TDoubleArrayList(); + data_gap = new TDoubleArrayList(); + } + + public BedHeight(String name) { + super(name); + heights = new TDoubleArrayList(); + station = new TDoubleArrayList(); + data_gap = new TDoubleArrayList(); + } + + public BedHeight(int capacity) { + this(capacity, ""); + } + + public BedHeight(int capacity, String name) { + super(name); + heights = new TDoubleArrayList(capacity); + station = new TDoubleArrayList(capacity); + data_gap = new TDoubleArrayList(capacity); + } + + public void add(double value, double station, double gap) { + this.heights.add(value); + this.station.add(station); + this.data_gap.add(gap); + } + + public int size() { + return heights.size(); + } + + public double getHeight(int idx) { + return heights.getQuick(idx); + } + + public double [] getHeights() { + return heights.toNativeArray(); + } + + public double [] get(int idx) { + return get(idx, new double [3]); + } + + public double [] get(int idx, double [] dst) { + dst[0] = heights.getQuick(idx); + dst[1] = station.getQuick(idx); + dst[2] = data_gap.getQuick(idx); + return dst; + } + + public double minHeights() { + return heights.min(); + } + + public static void removeNaNs(TDoubleArrayList [] arrays) { + + int dest = 0; + + int A = arrays.length; + int N = arrays[0].size(); + + OUTER: for (int i = 0; i < N; ++i) { + for (int j = 0; j < A; ++j) { + TDoubleArrayList a = arrays[j]; + double v = a.getQuick(i); + if (Double.isNaN(v)) { + continue OUTER; + } + a.setQuick(dest, v); + } + ++dest; + } + + if (dest < N) { + for (int i = 0; i < A; ++i) { + arrays[i].remove(dest, N-dest); + } + } + } + + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { heights }); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,48 @@ +package de.intevation.flys.artifacts.model.minfo; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.BedHeightsArtifact; +import de.intevation.flys.artifacts.model.BlackboardDataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +public class BedHeightFacet +extends BlackboardDataFacet +implements FacetTypes { + + public BedHeightFacet(String description) { + this(STATIC_BEDHEIGHT, description); + } + + public BedHeightFacet(String name, String description) { + this.name = name; + this.description = description; + this.index = 0; + } + + /** + * Returns the data this facet requires. + * + * @param artifact the owner artifact. + * @param context the CallContext (ignored). + * + * @return the data. + */ + @Override + public Object getData(Artifact artifact, CallContext context) { + BedHeightsArtifact staticData = + (BedHeightsArtifact) artifact; + return staticData.getHeight(); + } + /** + * Create a deep copy of this Facet. + * @return a deep copy. + */ + @Override + public BedHeightFacet deepCopy() { + BedHeightFacet copy = new BedHeightFacet(description); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,156 @@ +package de.intevation.flys.artifacts.model.minfo; + + +import java.util.List; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.artifacts.cache.CacheFactory; +import de.intevation.flys.artifacts.model.StaticBedHeightCacheKey; +import de.intevation.flys.backend.SessionHolder; + +public class BedHeightFactory { + /** Private logger to use here. */ + private static Logger log = Logger.getLogger(BedHeightFactory.class); + + /** Query to get km and ws for wst_id and column_pos. */ + public static final String SQL_SELECT_SINGLE = + "SELECT height, station, data_gap FROM bed_height_single_values " + + "WHERE id = :height_id"; + + /** Query to get name for wst_id and column_pos. */ + public static final String SQL_SELECT_EPOCH = + "SELECT height, station FROM bed_height_epoch_values "+ + "WHERE id = :height_id"; + + /** Query to get name (description) for wst_id. */ + public static final String SQL_SELECT_DESCR_SINGLE = + "SELECT description FROM bed_height_single "+ + "WHERE id = :height_id"; + + /** Query to get name (description) for wst_id. */ + public static final String SQL_SELECT_DESCR_EPOCH = + "SELECT description from bed_height_epoch "+ + "WHERE id = :height_id"; + + + private BedHeightFactory() { + } + + + /** + * Get WKms for given column and wst_id, caring about the cache. + */ + public static BedHeight getHeight(String type, int height_id, int time) { + log.debug("BedHeightFactory.getHeight"); + Cache cache = CacheFactory.getCache(StaticBedHeightCacheKey.CACHE_NAME); + + StaticBedHeightCacheKey cacheKey; + + if (cache != null) { + cacheKey = new StaticBedHeightCacheKey(height_id, time); + Element element = cache.get(cacheKey); + if (element != null) { + log.debug("Got static bedheight values from cache"); + return (BedHeight)element.getValue(); + } + } + else { + cacheKey = null; + } + + BedHeight values = getBedHeightUncached(type, height_id, time); + + if (values != null && cacheKey != null) { + log.debug("Store static bed height values in cache."); + Element element = new Element(cacheKey, values); + cache.put(element); + } + return values; + } + + /** Get name for a WKms. */ + public static String getHeightName(String type, int height_id) { + log.debug("BedHeightFactory.getHeightName height_id/" + height_id); + + String name = null; + Session session = SessionHolder.HOLDER.get(); + + SQLQuery nameQuery = null; + if (type.equals("single")) { + nameQuery = session.createSQLQuery(SQL_SELECT_DESCR_SINGLE) + .addScalar("description", StandardBasicTypes.STRING); + nameQuery.setInteger("height_id", height_id); + } + else if (type.equals("epoch")) { + nameQuery = session.createSQLQuery(SQL_SELECT_DESCR_EPOCH) + .addScalar("description", StandardBasicTypes.STRING); + nameQuery.setInteger("height_id", height_id); + } + else { + return "none"; + } + List<String> names = nameQuery.list(); + if (names.size() >= 1) { + name = names.get(0); + } + + return name; + } + + + /** + * Get WKms from db. + * @param column the position columns value + * @param wst_id database id of the wst + * @return according WKms. + */ + public static BedHeight getBedHeightUncached( + String type, + int height_id, + int time) + { + if (log.isDebugEnabled()) { + log.debug("BedHeightFactory.getBedHeightUncached"); + } + + BedHeight height = new BedHeight(getHeightName(type, height_id)); + + Session session = SessionHolder.HOLDER.get(); + SQLQuery sqlQuery = null; + if (type.equals("single")) { + sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLE) + .addScalar("height", StandardBasicTypes.DOUBLE) + .addScalar("station", StandardBasicTypes.DOUBLE) + .addScalar("data_gap", StandardBasicTypes.DOUBLE); + sqlQuery.setInteger("height_id", height_id); + List<Object []> results = sqlQuery.list(); + + for (int i = 0; i <= results.size(); i++) { + Object[] row = results.get(i); + height.add((Double) row[0], (Double) row[1], (Double) row[2]); + } + } + else if (type.equals("epoch")) { + sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCH) + .addScalar("height", StandardBasicTypes.DOUBLE) + .addScalar("station", StandardBasicTypes.DOUBLE); + sqlQuery.setInteger("height_id", height_id); + List<Object []> results = sqlQuery.list(); + + for (int i = 0; i <= results.size(); i++) { + Object[] row = results.get(i); + height.add((Double) row[0], (Double) row[1], 0); + } + } + + return height; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverview.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,200 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.flys.utils.KMIndex; + +public class BedOverview +implements Serializable +{ + /** + * Serial version UId. + */ + private static final long serialVersionUID = -7967134407371364911L; + + public interface Filter { + boolean accept(KMIndex<List<Date>> entry); + + } // interface Filter + + + public static final Filter ACCEPT = new Filter() { + public boolean accept(KMIndex<List<Date>> entry) { + return true; + } + }; + + public static class KmFilter implements Filter { + + protected double km; + + public KmFilter (double km) { + this.km = km; + } + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getKm() == km) { + return true; + } + } + return false; + } + }; + + public static class DateFilter implements Filter { + + protected Date date; + + public DateFilter (Date date) { + this.date = date; + } + + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getValue().equals(this.date)) { + return true; + } + } + return false; + } + }; + + private static Logger log = Logger.getLogger(BedOverview.class); + + public static final double EPSILON = 1e-4; + + public static final String DATE_FORMAT = "dd.MM.yyyy"; + + public static final String SQL_SQ = + "SELECT" + + " so.km AS km," + + " so.datum AS datum " + + "FROM sohltest so " + + " JOIN station s" + + " ON so.stationid = s.stationid " + + " JOIN gewaesser g " + + " ON s.gewaesserid = g.gewaesserid " + + "WHERE" + + " g.name = :name AND" + + " so.km IS NOT NULL " + + "ORDER by" + + " so.km, so.datum"; + + protected String riverName; + + protected KMIndex<List<Date>> entries; + + public BedOverview() { + entries = new KMIndex<List<Date>>(); + } + + public BedOverview(String riverName) { + this(); + this.riverName = riverName; + } + + private static final boolean epsilonEquals(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + + protected void loadData(Session session) { + SQLQuery query = session.createSQLQuery(SQL_SQ) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("datum", StandardBasicTypes.DATE); + + query.setString("name", riverName); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("No river '" + riverName + "' found."); + } + + Double prevKm = -Double.MAX_VALUE; + List<Date> dates = new ArrayList<Date>(); + + for (Object [] row: list) { + Double km = (Double)row[0]; + if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) { + entries.add(prevKm, dates); + dates = new ArrayList<Date>(); + } + dates.add((Date)row[1]); + prevKm = km; + } + + if (!dates.isEmpty()) { + entries.add(prevKm, dates); + } + } + + public boolean load(Session session) { + + loadData(session); + + return true; + } + + + public void generateOverview(Document document) { + generateOverview(document, ACCEPT); + } + + public KMIndex<List<Date>> filter(Filter f) { + // TODO: Apply filter + return entries; + } + + public void generateOverview( + Document document, + Filter filter + ) { + KMIndex<List<Date>> filtered = filter(ACCEPT); + + Element sqElement = document.createElement("bed"); + + Element riverElement = document.createElement("river"); + + riverElement.setAttribute("name", riverName); + + sqElement.appendChild(riverElement); + + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + + Element kmE = document.createElement("km"); + + for (KMIndex.Entry<List<Date>> e: filtered) { + + List<Date> dates = e.getValue(); + + if (!dates.isEmpty()) { + Element dEs = document.createElement("dates"); + + for (Date d: dates) { + Element dE = document.createElement("date"); + + dE.setAttribute("value", df.format(d)); + + dEs.appendChild(dE); + } + + kmE.appendChild(dEs); + } + } + + sqElement.appendChild(kmE); + + document.appendChild(sqElement); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverviewFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,70 @@ +package de.intevation.flys.artifacts.model.minfo; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; +import org.hibernate.Session; + +import de.intevation.flys.artifacts.cache.CacheFactory; +import de.intevation.flys.backend.SedDBSessionHolder; + +public class BedOverviewFactory { + + private static Logger log = Logger.getLogger(BedOverviewFactory.class); + + public static final String CACHE_NAME = "sq-overviews"; + + private BedOverviewFactory() { + } + + + public static BedOverview getOverview(String river) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Looking for bed overview for river '" + river + "'"); + } + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + if (debug) { + log.debug("Cache not configured."); + } + return getUncached(river); + } + + String key = "bed-over-" + river; + + Element element = cache.get(key); + + if (element != null) { + if (debug) { + log.debug("Overview found in cache"); + } + return (BedOverview)element.getValue(); + } + + BedOverview overview = getUncached(river); + + if (overview != null) { + if (debug) { + log.debug("Store overview in cache."); + } + cache.put(new Element(key, overview)); + } + + return overview; + } + + public static BedOverview getUncached(String river) { + BedOverview overview = new BedOverview(river); + + Session session = SedDBSessionHolder.HOLDER.get(); + + return overview.load(session) ? overview : null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,106 @@ +package de.intevation.flys.artifacts.model.minfo; + +import gnu.trove.TDoubleArrayList; + +import java.io.Serializable; + + +public class BedParametersResult +implements Serializable +{ + protected TDoubleArrayList porosityCap; + protected TDoubleArrayList porositySub; + protected TDoubleArrayList loadDensityCap; + protected TDoubleArrayList loadDensitySub; + protected TDoubleArrayList kms; + + public BedParametersResult() { + + } + + public BedParametersResult( + TDoubleArrayList kms, + TDoubleArrayList porosityCap, + TDoubleArrayList porositySub, + TDoubleArrayList densityCap, + TDoubleArrayList densitySub + ) { + this.kms = kms; + this.porosityCap = porosityCap; + this.porositySub = porositySub; + this.loadDensityCap = densityCap; + this.loadDensitySub = densitySub; + } + + public double getPorosityCap(int ndx) { + return porosityCap.get(ndx); + } + + public double getPorositySub(int ndx) { + return porositySub.get(ndx); + } + + public double getLoadDensityCap(int ndx) { + return loadDensityCap.get(ndx); + } + + public double getLoadDensitySub(int ndx) { + return loadDensitySub.get(ndx); + } + + public double getPorosityCap(double km) { + if (kms.indexOf(km) >= 0) { + return porosityCap.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double getPorositySub(double km) { + if (kms.indexOf(km) >= 0) { + return porositySub.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double getLoadDensityCap(double km) { + if (kms.indexOf(km) >= 0) { + return loadDensityCap.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double getLoadDensitySub(double km) { + if (kms.indexOf(km) >= 0) { + return loadDensitySub.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double[][] getPorosityCapData() { + return new double[][] { + kms.toNativeArray(), + porosityCap.toNativeArray() + }; + } + + public double[][] getPorositySubData() { + return new double[][] { + kms.toNativeArray(), + porositySub.toNativeArray() + }; + } + + public double[][] getDensityCapData() { + return new double[][] { + kms.toNativeArray(), + loadDensityCap.toNativeArray() + }; + } + + public double[][] getDensitySubData() { + return new double[][] { + kms.toNativeArray(), + loadDensitySub.toNativeArray() + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,59 @@ +package de.intevation.flys.artifacts.model.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet for serving bed porosity data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedPorosityFacet extends DataFacet { + + private static final long serialVersionUID = 1L; + + private static Logger logger = Logger.getLogger(BedPorosityFacet.class); + + public BedPorosityFacet() { + } + + public BedPorosityFacet(int idx, String name, String description, + ComputeType type, String stateId, String hash) { + super(idx, name, description, type, hash, stateId); + } + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for bed porosity at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute(context, hash, + stateId, type, false); + + int ndx = index >> 8; + Object[] data = ((BedQualityResult[]) res.getData())[ndx].getParameters(); // TODO CAST TO SPECIFIC CLASS + + int ndy = index & 255; + return data != null && data.length > ndy ? data[ndy] : null; + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + BedPorosityFacet copy = new BedPorosityFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,331 @@ +package de.intevation.flys.artifacts.model.minfo; + +import gnu.trove.TDoubleArrayList; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.access.BedQualityAccess; +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.backend.SedDBSessionHolder; + + +public class BedQualityCalculation extends Calculation { + + private static final Logger logger = Logger + .getLogger(BedQualityCalculation.class); + + protected String river; + protected double from; + protected double to; + protected List<String> bedDiameter; + protected List<String> bedloadDiameter; + protected List<DateRange> ranges; + + public BedQualityCalculation() { + } + + public CalculationResult calculate(BedQualityAccess access) { + logger.info("BedQualityCalculation.calculate"); + + String river = access.getRiver(); + Double from = access.getFrom(); + Double to = access.getTo(); + List<String> bedDiameter = access.getBedDiameter(); + List<String> bedloadDiameter = access.getBedloadDiameter(); + List<DateRange> ranges = access.getDateRanges(); + + if (river == null) { + // TODO: i18n + addProblem("minfo.missing.river"); + } + + if (from == null) { + // TODO: i18n + addProblem("minfo.missing.from"); + } + + if (to == null) { + // TODO: i18n + addProblem("minfo.missing.to"); + } + + if (ranges == null) { + // TODO: i18n + addProblem("minfo.missing.periods"); + } + + if (!hasProblems()) { + this.river = river; + this.from = from; + this.to = to; + this.ranges = ranges; + this.bedDiameter = bedDiameter; + this.bedloadDiameter = bedloadDiameter; + + SedDBSessionHolder.acquire(); + try { + return internalCalculate(); + } + finally { + SedDBSessionHolder.release(); + } + } + + return new CalculationResult(); + } + + protected CalculationResult internalCalculate() { + + List<BedQualityResult> results = new LinkedList<BedQualityResult>(); + // Calculate for all time periods. + for (DateRange dr : ranges) { + QualityMeasurements loadMeasurements = + QualityMeasurementFactory.getBedloadMeasurements( + river, + from, + to, + dr.getFrom(), + dr.getTo()); + QualityMeasurements bedMeasurements = + QualityMeasurementFactory.getBedMeasurements( + river, + from, + to, + dr.getFrom(), + dr.getTo()); + BedQualityResult result = new BedQualityResult(); + result.setDateRange(dr); + if (bedDiameter != null) { + result.add(calculateBedParameter(bedMeasurements, dr)); + for (String bd : bedDiameter) { + BedDiameterResult bedResult = + calculateBed(bedMeasurements, bd, dr); + + // Avoid adding empty result sets. + if (!bedResult.isEmpty()) { + result.add(bedResult); + } + } + } + if (bedloadDiameter != null) { + for (String bld : bedloadDiameter) { + BedloadDiameterResult loadResult = + calculateBedload(loadMeasurements, bld, dr); + result.add(loadResult); + } + } + results.add(result); + } + + return new CalculationResult( + results.toArray(new BedQualityResult[results.size()]), this); + } + + private BedParametersResult calculateBedParameter( + QualityMeasurements qm, + DateRange dr + ) { + List<Double> kms = qm.getKms(); + QualityMeasurements capFiltered = filterCapMeasurements(qm); + QualityMeasurements subFiltered = filterSubMeasurements(qm); + TDoubleArrayList location = new TDoubleArrayList(); + TDoubleArrayList porosityCap = new TDoubleArrayList(); + TDoubleArrayList porositySub = new TDoubleArrayList(); + TDoubleArrayList densityCap = new TDoubleArrayList(); + TDoubleArrayList densitySub = new TDoubleArrayList(); + + for(double km : kms) { + double[] pCap = calculatePorosity(capFiltered, km); + double[] pSub = calculatePorosity(subFiltered, km); + double[] dCap = calculateDensity(capFiltered, pCap); + double[] dSub = calculateDensity(subFiltered, pSub); + + double pCapRes = 0d; + double pSubRes = 0d; + double dCapRes = 0d; + double dSubRes = 0d; + for (int i = 0; i < pCap.length; i++) { + pCapRes += pCap[i]; + dCapRes += dCap[i]; + } + for (int i = 0; i < pSub.length; i++) { + pSubRes += pSub[i]; + dSubRes += dSub[i]; + } + location.add(km); + porosityCap.add((pCapRes / pCap.length) * 100 ); + porositySub.add((pSubRes / pSub.length) * 100); + densityCap.add((dCapRes / dCap.length) / 1000); + densitySub.add((dSubRes / dSub.length) / 1000); + + } + + return new BedParametersResult( + location, + porosityCap, + porositySub, + densityCap, + densitySub); + } + + protected BedDiameterResult calculateBed( + QualityMeasurements qm, + String diameter, + DateRange range + ) { + List<Double> kms = qm.getKms(); + TDoubleArrayList location = new TDoubleArrayList(); + TDoubleArrayList avDiameterCap = new TDoubleArrayList(); + TDoubleArrayList avDiameterSub = new TDoubleArrayList(); + for (double km : kms) { + //Filter cap and sub measurements. + QualityMeasurements capFiltered = filterCapMeasurements(qm); + QualityMeasurements subFiltered = filterSubMeasurements(qm); + + List<QualityMeasurement> cm = capFiltered.getMeasurements(km); + List<QualityMeasurement> sm = subFiltered.getMeasurements(km); + + double avCap = calculateAverage(cm, diameter); + double avSub = calculateAverage(sm, diameter); + location.add(km); + avDiameterCap.add(avCap); + avDiameterSub.add(avSub); + } + return new BedDiameterResult( + diameter, + avDiameterCap, + avDiameterSub, + location); + } + + private double[] calculateDensity( + QualityMeasurements capFiltered, + double[] porosity + ) { + double[] density = new double[porosity.length]; + for (int i = 0; i < porosity.length; i++) { + density[i] = (1 - porosity[i]) * 2650; + } + return density; + } + + private double[] calculatePorosity( + QualityMeasurements capFiltered, + double km + ) { + List<QualityMeasurement> list = capFiltered.getMeasurements(km); + double[] results = new double[list.size()]; + int i = 0; + for (QualityMeasurement qm : list) { + double deviation = calculateDeviation(qm); + double p = calculateP(qm); + double porosity = 0.353 - 0.068 * deviation + 0.146 * p; + results[i] = porosity; + i++; + } + + return results; + } + + protected BedloadDiameterResult calculateBedload( + QualityMeasurements qm, + String diameter, + DateRange range + ) { + List<Double> kms = qm.getKms(); + TDoubleArrayList location = new TDoubleArrayList(); + TDoubleArrayList avDiameter = new TDoubleArrayList(); + for (double km : kms) { + List<QualityMeasurement> measurements = qm.getMeasurements(km); + double mid = calculateAverage(measurements, diameter); + location.add(km); + avDiameter.add(mid); + } + return new BedloadDiameterResult( + diameter, + avDiameter, + location, + range); + } + + protected double calculateAverage( + List<QualityMeasurement> list, + String diameter + ) { + double av = 0; + for (QualityMeasurement qm : list) { + av += qm.getDiameter(diameter); + } + return av/list.size(); + } + + protected QualityMeasurements filterCapMeasurements( + QualityMeasurements qms + ) { + List<QualityMeasurement> result = new LinkedList<QualityMeasurement>(); + for (QualityMeasurement qm : qms.getMeasurements()) { + if (qm.getDepth1() == 0d && qm.getDepth2() <= 0.3) { + result.add(qm); + } + } + return new QualityMeasurements(result); + } + + protected QualityMeasurements filterSubMeasurements( + QualityMeasurements qms + ) { + List<QualityMeasurement> result = new LinkedList<QualityMeasurement>(); + for (QualityMeasurement qm : qms.getMeasurements()) { + if (qm.getDepth1() > 0d && qm.getDepth2() <= 0.5) { + result.add(qm); + } + } + return new QualityMeasurements(result); + } + + public double calculateDeviation(QualityMeasurement qm) { + Map<String, Double> dm = qm.getAllDiameter(); + double phiM = 0; + double[] phis = new double[dm.size()]; + double[] ps = new double[dm.size()]; + int i = 0; + for (String key : dm.keySet()) { + double d = dm.get(key); + double phi = -Math.log(d)/Math.log(2); + phis[i] = phi; + double p = calculateWeight(qm, key); + ps[i] = p; + phiM += phi * p; + i++; + } + + double sig = 0d; + for (i = 0; i < dm.size(); i++) { + sig += ps[i] * Math.exp(phis[i] - phiM); + } + double deviation = Math.sqrt(sig); + return deviation; + } + + protected double calculateP(QualityMeasurement qm) { + return calculateWeight(qm, "dmin"); + } + + public double calculateWeight(QualityMeasurement qm, String diameter) { + Map<String, Double> dm = qm.getAllDiameter(); + double value = qm.getDiameter(diameter); + + double sum = 0d; + for (Double d : dm.values()) { + sum =+ d.doubleValue(); + } + double weight = sum/100*value; + return weight; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityDiameterResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.model.minfo; + +import gnu.trove.TDoubleArrayList; + +import java.io.Serializable; + +public class BedQualityDiameterResult implements Serializable { + + public static enum DIAMETER_TYPE { + D90, + D84, + D80, + D75, + D70, + D60, + D50, + D40, + D30, + D25, + D20, + D16, + D10, + DMIN, + DMAX + } + + protected DIAMETER_TYPE type; + protected TDoubleArrayList kms; + protected boolean empty; + + public BedQualityDiameterResult () { + empty = true; + } + + public BedQualityDiameterResult ( + String type, + TDoubleArrayList km + ) { + if (km.size() > 0) { + empty = false; + } + this.type = DIAMETER_TYPE.valueOf(type.toUpperCase()); + this.kms = km; + } + + public DIAMETER_TYPE getType() { + return this.type; + } + + public TDoubleArrayList getKms() { + return this.kms; + } + + public void setType(DIAMETER_TYPE type) { + this.type = type; + } + + public boolean isEmpty() { + return empty; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,69 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import de.intevation.flys.artifacts.model.DateRange; + +public class BedQualityResult +implements Serializable +{ + + protected List<BedDiameterResult> bedResults; + protected List<BedloadDiameterResult> bedloadResults; + protected List<BedParametersResult> bedParameters; + protected DateRange dateRange; + + public BedQualityResult () { + bedResults = new LinkedList<BedDiameterResult>(); + bedloadResults = new LinkedList<BedloadDiameterResult>(); + bedParameters = new LinkedList<BedParametersResult>(); + }; + + public BedQualityResult ( + List<BedDiameterResult> bedResults, + List<BedloadDiameterResult> bedloadResults, + List<BedParametersResult> bedParameters, + DateRange range + ) { + this.dateRange = range; + this.bedResults = bedResults; + this.bedloadResults = bedloadResults; + this.bedParameters = bedParameters; + } + + public BedParametersResult[] getParameters() { + return bedParameters.toArray( + new BedParametersResult[bedParameters.size()]); + } + + public BedDiameterResult[] getBedResults() { + return bedResults.toArray(new BedDiameterResult[bedResults.size()]); + } + + public BedloadDiameterResult[] getBedloadResults() { + return bedloadResults.toArray( + new BedloadDiameterResult[bedloadResults.size()]); + } + + public void add(BedloadDiameterResult result) { + bedloadResults.add(result); + } + + public void add(BedDiameterResult result) { + bedResults.add(result); + } + + public void add(BedParametersResult result) { + bedParameters.add(result); + } + + public DateRange getDateRange() { + return dateRange; + } + + public void setDateRange(DateRange range) { + this.dateRange = range; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.model.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet for serving bedload diameter data. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedloadDiameterFacet extends DataFacet { + + private static final long serialVersionUID = 1L; + + private static Logger logger = Logger.getLogger(BedloadDiameterFacet.class); + + public BedloadDiameterFacet() { + // required for clone operation deepCopy() + } + + public BedloadDiameterFacet(int idx, String name, String description, + ComputeType type, String stateId, String hash) { + super(idx, name, description, type, hash, stateId); + } + + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for bedload diameter at index: " + index); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute(context, hash, + stateId, type, false); + + int ndx = index >> 8; + Object[] data = + ((BedQualityResult[]) res.getData())[ndx].getBedloadResults(); // TODO CAST TO SPECIFIC CLASS + + int ndy = index & 255; + return data != null && data.length > ndy ? data[ndy] : null; + } + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + BedloadDiameterFacet copy = new BedloadDiameterFacet(); + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,42 @@ +package de.intevation.flys.artifacts.model.minfo; + +import de.intevation.flys.artifacts.model.DateRange; +import gnu.trove.TDoubleArrayList; + + +public class BedloadDiameterResult +extends BedQualityDiameterResult +{ + protected TDoubleArrayList diameter; + + public BedloadDiameterResult( + String type, + TDoubleArrayList diameter, + TDoubleArrayList km, + DateRange range + ) { + super (type, km); + this.diameter = diameter; + } + + public double getDiameter(int ndx) { + if (diameter != null) { + return this.diameter.get(ndx); + } + return Double.NaN; + } + + public double getDiameter(double km) { + if (kms.indexOf(km) >= 0) { + return diameter.get(kms.indexOf(km)); + } + return Double.NaN; + } + + public double[][] getDiameterData() { + return new double[][] { + kms.toNativeArray(), + diameter.toNativeArray() + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,198 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.flys.utils.KMIndex; + +public class BedloadOverview implements Serializable { + + private static Logger log = Logger.getLogger(BedloadOverview.class); + + /** + * Serial version UId. + */ + private static final long serialVersionUID = -7607668985959407096L; + + public interface Filter { + boolean accept(KMIndex<List<Date>> entry); + + } // interface Filter + + + public static final Filter ACCEPT = new Filter() { + public boolean accept(KMIndex<List<Date>> entry) { + return true; + } + }; + + public static class KmFilter implements Filter { + + protected double km; + + public KmFilter (double km) { + this.km = km; + } + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getKm() == km) { + return true; + } + } + return false; + } + }; + + public static class DateFilter implements Filter { + + protected Date date; + + public DateFilter (Date date) { + this.date = date; + } + + public boolean accept(KMIndex<List<Date>> list) { + for (KMIndex.Entry<List<Date>> e: list){ + if (e.getValue().equals(this.date)) { + return true; + } + } + return false; + } + }; + + public static final double EPSILON = 1e-4; + + public static final String DATE_FORMAT = "dd.MM.yyyy"; + + public static final String SQL_SQ = + "SELECT" + + " m.km AS km," + + " m.datum AS datum " + + "FROM messung m " + + " JOIN station s" + + " ON m.stationid = s.stationid " + + " JOIN gewaesser g " + + " ON s.gewaesserid = g.gewaesserid " + + "WHERE" + + " g.name = :name " + + "ORDER by" + + " m.km, m.datum"; + + protected String riverName; + + protected KMIndex<List<Date>> entries; + + public BedloadOverview() { + entries = new KMIndex<List<Date>>(); + } + + public BedloadOverview(String riverName) { + this(); + this.riverName = riverName; + } + + private static final boolean epsilonEquals(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + + protected void loadData(Session session) { + SQLQuery query = session.createSQLQuery(SQL_SQ) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("datum", StandardBasicTypes.DATE); + + query.setString("name", riverName); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("No river '" + riverName + "' found."); + } + + Double prevKm = -Double.MAX_VALUE; + List<Date> dates = new ArrayList<Date>(); + + for (Object [] row: list) { + Double km = (Double)row[0]; + if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) { + entries.add(prevKm, dates); + dates = new ArrayList<Date>(); + } + dates.add((Date)row[1]); + prevKm = km; + } + + if (!dates.isEmpty()) { + entries.add(prevKm, dates); + } + } + + public boolean load(Session session) { + + loadData(session); + + return true; + } + + + public void generateOverview(Document document) { + generateOverview(document, ACCEPT); + } + + public KMIndex<List<Date>> filter(Filter f) { + // TODO: Apply filter + return entries; + } + + public void generateOverview( + Document document, + Filter filter + ) { + KMIndex<List<Date>> filtered = filter(ACCEPT); + + Element sqElement = document.createElement("bedload"); + + Element riverElement = document.createElement("river"); + + riverElement.setAttribute("name", riverName); + + sqElement.appendChild(riverElement); + + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + + Element kmE = document.createElement("km"); + + for (KMIndex.Entry<List<Date>> e: filtered) { + + List<Date> dates = e.getValue(); + + if (!dates.isEmpty()) { + Element dEs = document.createElement("dates"); + + for (Date d: dates) { + Element dE = document.createElement("date"); + + dE.setAttribute("value", df.format(d)); + + dEs.appendChild(dE); + } + + kmE.appendChild(dEs); + } + } + + sqElement.appendChild(kmE); + + document.appendChild(sqElement); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverviewFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,70 @@ +package de.intevation.flys.artifacts.model.minfo; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import org.apache.log4j.Logger; +import org.hibernate.Session; + +import de.intevation.flys.artifacts.cache.CacheFactory; +import de.intevation.flys.backend.SedDBSessionHolder; + +public class BedloadOverviewFactory { + + private static Logger log = Logger.getLogger(BedloadOverviewFactory.class); + + public static final String CACHE_NAME = "sq-overviews"; + + private BedloadOverviewFactory() { + } + + + public static BedloadOverview getOverview(String river) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Looking for bedload overview for river '" + river + "'"); + } + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + if (debug) { + log.debug("Cache not configured."); + } + return getUncached(river); + } + + String key = "bedload-over-" + river; + + Element element = cache.get(key); + + if (element != null) { + if (debug) { + log.debug("Overview found in cache"); + } + return (BedloadOverview)element.getValue(); + } + + BedloadOverview overview = getUncached(river); + + if (overview != null) { + if (debug) { + log.debug("Store overview in cache."); + } + cache.put(new Element(key, overview)); + } + + return overview; + } + + public static BedloadOverview getUncached(String river) { + BedloadOverview overview = new BedloadOverview(river); + + Session session = SedDBSessionHolder.HOLDER.get(); + + return overview.load(session) ? overview : null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,80 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.util.Date; +import java.util.Map; + + +public class QualityMeasurement { + + private double km; + private Date date; + private double depth1; + private double depth2; + private Map<String, Double> charDiameter; + + public QualityMeasurement() { + + } + + public QualityMeasurement( + double km, + Date date, + double depth1, + double depth2, + Map<String, Double> diameter) { + this.setKm(km); + this.setDate(date); + this.depth1 = depth1; + this.depth2 = depth2; + this.setDiameter(diameter); + } + + public double getKm() { + return km; + } + + public void setKm(double km) { + this.km = km; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Map<String, Double> getAllDiameter() { + return charDiameter; + } + + public void setDiameter(Map<String, Double> charDiameter) { + this.charDiameter = charDiameter; + } + + public double getDiameter(String key) { + return charDiameter.get(key); + } + + public void setDiameter(String key, double value) { + charDiameter.put(key, value); + } + + public double getDepth1() { + return depth1; + } + + public void setDepth1(double depth1) { + this.depth1 = depth1; + } + + public double getDepth2() { + return depth2; + } + + public void setDepth2(double depth2) { + this.depth2 = depth2; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,203 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.transform.BasicTransformerAdapter; +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.backend.SedDBSessionHolder; + + +public class QualityMeasurementFactory { + + private static Logger logger = Logger.getLogger(QualityMeasurementFactory.class); + + private static final String SQL_BED_MEASUREMENT = + "SELECT st.km as km," + + " st.datum as datum," + + " sp.tiefevon as depth1," + + " sp.tiefebis as depth2," + + " sa.d10 as d10," + + " sa.d16 as d16," + + " sa.d20 as d20," + + " sa.d25 as d25," + + " sa.d30 as d30," + + " sa.d40 as d40," + + " sa.d50 as d50," + + " sa.d60 as d60," + + " sa.d70 as d70," + + " sa.d75 as d75," + + " sa.d80 as d80," + + " sa.d84 as d84," + + " sa.d90 as d90," + + " sa.dmin as dmin," + + " sa.dmax as dmax " + + "FROM sohltest st " + + " JOIN station sn ON sn.stationid = st.stationid " + + " JOIN gewaesser gw ON gw.gewaesserid = sn.gewaesserid " + + " JOIN sohlprobe sp ON sp.sohltestid = st.sohltestid " + + " JOIN siebanalyse sa ON sa.sohlprobeid = sp.sohlprobeid " + + "WHERE gw.name = :name AND " + + " st.km IS NOT NULL AND " + + " sp.tiefevon IS NOT NULL AND " + + " sp.tiefebis IS NOT NULL AND " + // TODO: Test if char diameter ist null. + " st.km BETWEEN :from - 0.001 AND :to + 0.001 AND " + + " st.datum BETWEEN :start AND :end"; + + private static final String SQL_BEDLOAD_MEASUREMENT = + "SELECT m.km as km," + + " m.datum as datum," + + " m.d10 as d10," + + " m.d16 as d16," + + " m.d20 as d20," + + " m.d25 as d25," + + " m.d30 as d30," + + " m.d40 as d40," + + " m.d50 as d50," + + " m.d60 as d60," + + " m.d70 as d70," + + " m.d75 as d75," + + " m.d80 as d80," + + " m.d84 as d84," + + " m.d90 as d90," + + " m.dmin as dmin," + + " m.dmax as dmax " + + "FROM messung m" + + " JOIN station sn ON sn.stationid = m.stationid" + + " JOIN gewaesser gw ON gw.gewaesserid = sn.gewaesserid " + + "WHERE gw.name = :name AND " + + " m.km IS NOT NULL AND " + + " m.d10 IS NOT NULL AND" + //TODO: Add all other char. diameter. + " m.km BETWEEN :from - 0.001 AND :to + 0.001 AND" + + " m.datum BETWEEN :start AND :end"; + + public static final class QualityMeasurementResultTransformer + extends BasicTransformerAdapter { + + public static QualityMeasurementResultTransformer INSTANCE = new QualityMeasurementResultTransformer(); + + public QualityMeasurementResultTransformer() { + } + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + Map<String, Double> map = new HashMap<String, Double>(); + double km = 0; + Date d = null; + double depth1 = Double.NaN; + double depth2 = Double.NaN; + for (int i = 0; i < tuple.length; ++i) { + if (tuple[i] != null) { + if (aliases[i].equals("km")) { + km = ((Number) tuple[i]).doubleValue(); + } + else if (aliases[i].equals("datum")) { + d = (Date) tuple[i]; + } + else if (aliases[i].equals("depth1")) { + depth1 = ((Number) tuple[i]).doubleValue(); + } + else if (aliases[i].equals("depth2")) { + depth2 = ((Number) tuple[i]).doubleValue(); + } + else { + map.put(aliases[i], ((Double) tuple[i])/1000); + } + } + } + return new QualityMeasurement(km, d, depth1, depth2, map); + } + } // class BasicTransformerAdapter + + private QualityMeasurementFactory() { + } + + protected static QualityMeasurements load( + Session session, + String river, + double from, + double to, + Date start, + Date end, + String statement + ) { + SQLQuery query = session.createSQLQuery(statement) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("datum", StandardBasicTypes.DATE) + .addScalar("d10", StandardBasicTypes.DOUBLE) + .addScalar("d16", StandardBasicTypes.DOUBLE) + .addScalar("d20", StandardBasicTypes.DOUBLE) + .addScalar("d25", StandardBasicTypes.DOUBLE) + .addScalar("d30", StandardBasicTypes.DOUBLE) + .addScalar("d40", StandardBasicTypes.DOUBLE) + .addScalar("d50", StandardBasicTypes.DOUBLE) + .addScalar("d60", StandardBasicTypes.DOUBLE) + .addScalar("d70", StandardBasicTypes.DOUBLE) + .addScalar("d75", StandardBasicTypes.DOUBLE) + .addScalar("d80", StandardBasicTypes.DOUBLE) + .addScalar("d84", StandardBasicTypes.DOUBLE) + .addScalar("d90", StandardBasicTypes.DOUBLE) + .addScalar("dmin", StandardBasicTypes.DOUBLE) + .addScalar("dmax", StandardBasicTypes.DOUBLE); + + if (statement.equals(SQL_BED_MEASUREMENT)) { + query.addScalar("depth1", StandardBasicTypes.DOUBLE); + query.addScalar("depth2", StandardBasicTypes.DOUBLE); + } + + query.setString("name", river); + query.setDouble("from", from); + query.setDouble("to", to); + query.setDate("start", start); + query.setDate("end", end); + + query.setResultTransformer( + QualityMeasurementResultTransformer.INSTANCE); + + return new QualityMeasurements(query.list()); + } + + public static QualityMeasurements getBedMeasurements( + String river, + double from, + double to, + Date start, + Date end) { + Session session = SedDBSessionHolder.HOLDER.get(); + try { + return load(session, river, from, to, start, end, + SQL_BED_MEASUREMENT); + } + finally { + //session.close(); + } + } + + public static QualityMeasurements getBedloadMeasurements( + String river, + double from, + double to, + Date start, + Date end + ) { + Session session = SedDBSessionHolder.HOLDER.get(); + try { + return load( + session, + river, + from, + to, + start, + end, + SQL_BEDLOAD_MEASUREMENT); + } + finally { + //session.close(); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,50 @@ +package de.intevation.flys.artifacts.model.minfo; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class QualityMeasurements { + private static Logger logger = Logger.getLogger(QualityMeasurements.class); + private List<QualityMeasurement> measurements; + + public QualityMeasurements() { + } + + public QualityMeasurements(List<QualityMeasurement> list) { + measurements = list; + } + + public List<QualityMeasurement> getMeasurements() { + return measurements; + } + + public List<QualityMeasurement> getMeasurements(double km) { + List<QualityMeasurement> res = new LinkedList<QualityMeasurement>(); + for (QualityMeasurement qm: measurements) { + if (qm.getKm() == km) { + res.add(qm); + } + } + return res; + } + + public List<Double> getKms() { + List<Double> result = new LinkedList<Double>(); + for (QualityMeasurement qm : measurements) { + if (result.indexOf(qm.getKm()) < 0) { + result.add(qm.getKm()); + } + } + return result; + } + + public void setMeasurements(List<QualityMeasurement> list) { + this.measurements = list; + } + + public void addMeasurement(QualityMeasurement qm) { + this.measurements.add(qm); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,149 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.flys.artifacts.math.fitting.Function; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.math.MathException; + +import org.apache.commons.math.optimization.fitting.CurveFitter; + +import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; + +import org.apache.log4j.Logger; + +public class Fitting +implements Outlier.Callback +{ + private static Logger log = Logger.getLogger(Fitting.class); + + public interface Callback { + + void afterIteration( + double [] parameters, + SQ [] measurements, + SQ [] outliers, + double standardDeviation, + double chiSqr); + } // interfacte + + protected Function function; + + protected double [] coeffs; + + protected de.intevation.flys.artifacts.math.Function instance; + + protected double stdDevFactor; + protected double chiSqr; + + protected Callback callback; + + public Fitting() { + } + + public Fitting(Function function, double stdDevFactor) { + this(); + this.function = function; + this.stdDevFactor = stdDevFactor; + } + + public Function getFunction() { + return function; + } + + public void setFunction(Function function) { + this.function = function; + } + + public double getStdDevFactor() { + return stdDevFactor; + } + + public void setStdDevFactor(double stdDevFactor) { + this.stdDevFactor = stdDevFactor; + } + + @Override + public void initialize(List<SQ> sqs) throws MathException { + + LevenbergMarquardtOptimizer lmo = + new LevenbergMarquardtOptimizer(); + + CurveFitter cf = new CurveFitter(lmo); + for (SQ sq: sqs) { + cf.addObservedPoint(sq.getQ(), sq.getS()); + } + + coeffs = cf.fit( + function, function.getInitialGuess()); + + instance = function.instantiate(coeffs); + + chiSqr = lmo.getChiSquare(); + } + + @Override + public double eval(SQ sq) { + double s = instance.value(sq.q); + return sq.s - s; + } + + @Override + public void iterationFinished( + double standardDeviation, + SQ outlier, + List<SQ> remainings + ) { + if (log.isDebugEnabled()) { + log.debug("iterationFinished ----"); + log.debug(" num remainings: " + remainings.size()); + log.debug(" has outlier: " + outlier != null); + log.debug(" standardDeviation: " + standardDeviation); + log.debug(" Chi^2: " + chiSqr); + log.debug("---- iterationFinished"); + } + callback.afterIteration( + coeffs, + remainings.toArray(new SQ[remainings.size()]), + outlier != null ? new SQ [] { outlier} : new SQ [] {}, + standardDeviation, + chiSqr); + } + + protected static final List<SQ> onlyValid(List<SQ> sqs) { + + List<SQ> good = new ArrayList<SQ>(sqs.size()); + + for (SQ sq: sqs) { + if (sq.isValid()) { + good.add(sq); + } + } + + return good; + } + + public boolean fit(List<SQ> sqs, Callback callback) { + + sqs = onlyValid(sqs); + + if (sqs.size() < 2) { + log.warn("Too less points for fitting."); + return false; + } + + this.callback = callback; + + try { + Outlier.detectOutliers(this, sqs, stdDevFactor); + } + catch (MathException me) { + log.warn(me); + return false; + } + + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,88 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.util.Map; + +public class Measurement +{ + protected Map<String, Object> data; + + public Measurement() { + } + + public Measurement(Map<String, Object> data) { + this.data = data; + } + + protected double get(String name) { + Number value = (Number)data.get(name); + return value != null ? value.doubleValue() : Double.NaN; + } + + public double S_SS() { + return get("TSAND"); + } + + public double S_SF() { + return get("TSCHWEB") - get("TSAND"); + } + + public double Q() { + return get("Q_BPEGEL"); + } + + public double TOTAL_BL() { + // TODO: Implement me! + return Double.NaN; + } + + public double SAND() { + // TODO: Implement me! + return Double.NaN; + } + + + public double S_BL_S() { + return SAND() * TOTAL_BL(); + } + + public double S_BL_FG() { + // TODO: Implement me! + return Double.NaN; + } + + public double S_BL_CG() { + // TODO: Implement me! + return Double.NaN; + } + + public double S_BL() { + // TODO: Implement me! + return Double.NaN; + } + + public double S_BL_1() { + return S_BL_S() + S_BL_FG() + S_BL_CG(); + } + + public double S_BL_2() { + return S_SS() + S_BL_S() + S_BL_FG() + S_BL_CG(); + } + + public double SIEB(int i) { + return get(String.format("SIEB%02d", i)); + } + + public double RSIEB(int i) { + return get(String.format("RSIEB%02d", i)); + } + + public double REST() { + return get("REST"); + } + + @Override + public String toString() { + return "Measurement: " + data; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,157 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.flys.artifacts.model.DateRange; + +import de.intevation.flys.backend.SedDBSessionHolder; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.transform.BasicTransformerAdapter; + +import org.hibernate.type.StandardBasicTypes; + +public class MeasurementFactory +{ + private static final Logger log = + Logger.getLogger(MeasurementFactory.class); + + public static final String [] GSIEBSATZ = { + "SIEB01", "SIEB02", "SIEB03", "SIEB04", + "SIEB05", "SIEB06", "SIEB07", "SIEB08", + "SIEB09", "SIEB10", "SIEB11", "SIEB13", + "SIEB13", "SIEB14", "SIEB15", "SIEB16", + "SIEB17", "SIEB18", "SIEB19", "SIEB20", + "SIEB21" + }; + + public static final String [] SSIEBUNG = { + "RSIEB01", "RSIEB02", "RSIEB03", "RSIEB04", + "RSIEB05", "RSIEB06", "RSIEB07", "RSIEB08", + "RSIEB09", "RSIEB10", "RSIEB11", "RSIEB13", + "RSIEB13", "RSIEB14", "RSIEB15", "RSIEB16", + "RSIEB17", "RSIEB18", "RSIEB19", "RSIEB20", + "RSIEB21", "REST" + }; + + public static final String SQL_MEASSURE = + ("SELECT " + + "m.TSAND AS TSAND," + + "m.TSCHWEB AS TSCHWEB," + + "m.CSCHWEB AS CSCHWEB," + + "m.Q_BPEGEL AS Q_BPEGEL " + + // ", %GSIEBSATZ% " + + // "%SSIEBUNG% " + + "FROM messung m " + + "JOIN station s ON m.stationid = s.stationid " + + "JOIN gewaesser g ON s.gewaesserid = g.gewaesserid " + + // "LEFT JOIN GSIEBSATZ gs ON m.gsiebsatzid = gs.gsiebsatzid " + + // "LEFT JOIN SSIEBUNG ss ON gs.gsiebsatzid = ss.gsiebsatzid " + + "WHERE " + + "g.name = :river_name " + + "AND m.Q_BPEGEL IS NOT NULL " + + "AND s.km BETWEEN :location - 0.001 AND :location + 0.001 " + + "AND m.datum BETWEEN :from AND :to "); + //.replace("%GSIEBSATZ%", projection("gs", GSIEBSATZ)); + //.replace("%SSIEBUNG%", projection("ss", SSIEBUNG)); + + private static final String projection( + String prefix, + String [] columnNames + ) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < columnNames.length; ++i) { + if (i > 0) { + sb.append(','); + } + sb.append(prefix) + .append('.') + .append(columnNames[i]) + .append(" AS ") + .append(columnNames[i]); + } + return sb.toString(); + } + + public static final class MeasurementResultTransformer + extends BasicTransformerAdapter + { + public static MeasurementResultTransformer INSTANCE = + new MeasurementResultTransformer(); + + public MeasurementResultTransformer() { + } + + @Override + public Object transformTuple(Object [] tuple, String [] aliases) { + Map<String, Object> map = new HashMap<String, Object>(); + for (int i = 0; i < tuple.length; ++i) { + if (tuple[i] != null) { + map.put(aliases[i], tuple[i]); + } + } + return new Measurement(map); + } + } // class BasicTransformerAdapter + + private MeasurementFactory() { + } + + protected static Measurements load( + Session session, + String river, + double location, + DateRange dateRange + ) { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug(SQL_MEASSURE); + } + + SQLQuery query = session.createSQLQuery(SQL_MEASSURE) + .addScalar("TSAND", StandardBasicTypes.DOUBLE) + .addScalar("TSCHWEB", StandardBasicTypes.DOUBLE) + .addScalar("CSCHWEB", StandardBasicTypes.DOUBLE) + .addScalar("Q_BPEGEL", StandardBasicTypes.DOUBLE); + + /* + for (String siebsatz: GSIEBSATZ) { + query.addScalar(siebsatz, StandardBasicTypes.DOUBLE); + } + + for (String siebung: SSIEBUNG) { + query.addScalar(siebung, StandardBasicTypes.DOUBLE); + } + */ + + query.setString("river_name", river); + query.setDouble("location", location); + query.setDate("from", dateRange.getFrom()); + query.setDate("to", dateRange.getTo()); + + query.setResultTransformer(MeasurementResultTransformer.INSTANCE); + + return new Measurements(query.list()); + } + + public static Measurements getMeasurements( + String river, + double location, + DateRange dateRange + ) { + Session session = SedDBSessionHolder.HOLDER.get(); + try { + return load(session, river, location, dateRange); + } + finally { + session.close(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,125 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class Measurements +{ + private static final Logger log = Logger.getLogger(Measurements.class); + + public interface SExtractor { + double getS(Measurement measument); + } // interface SExtractor + + public static final SExtractor S_SF_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_SF(); + } + }; + + public static final SExtractor S_SS_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_SS(); + } + }; + + public static final SExtractor S_BL_S_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_BL_S(); + } + }; + + public static final SExtractor S_BL_FG_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_BL_FG(); + } + }; + + public static final SExtractor S_BL_CG_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_BL_CG(); + } + }; + + public static final SExtractor S_BL_EXTRACTOR = new SExtractor() { + @Override + public double getS(Measurement measument) { + return measument.S_BL(); + } + }; + + protected List<Measurement> measuments; + + public Measurements() { + } + + public Measurements(List<Measurement> measuments) { + this.measuments = measuments; + } + + public List<SQ> extractSQ(SExtractor extractor) { + List<SQ> result = new ArrayList(measuments.size()); + for (Measurement measument: measuments) { + SQ sq = new SQ(extractor.getS(measument), measument.Q()); + if (sq.isValid()) { + result.add(sq); + } + } + return result; + } + + public List<SQ> S_SF() { + return extractSQ(S_SF_EXTRACTOR); + } + + public List<SQ> S_SS() { + return extractSQ(S_SS_EXTRACTOR); + } + + public List<SQ> S_BL_S() { + return extractSQ(S_BL_S_EXTRACTOR); + } + + public List<SQ> S_BL_FG() { + return extractSQ(S_BL_FG_EXTRACTOR); + } + + public List<SQ> S_BL_CG() { + return extractSQ(S_BL_CG_EXTRACTOR); + } + + public List<SQ> S_BL() { + return extractSQ(S_BL_EXTRACTOR); + } + + public List<SQ> getSQs(int index) { + switch (index) { + case 0: return S_SF(); + case 1: return S_SS(); + case 2: return S_BL_S(); + case 3: return S_BL_FG(); + case 4: return S_BL_CG(); + case 5: return S_BL(); + } + log.error("THIS SHOULD NOT HAPPEN: Tried to access SQ[" + index + "]"); + return new ArrayList<SQ>(0); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Measurements ["); + for (int i = 0, M = measuments.size(); i < M; ++i) { + if (i > 0) sb.append(", "); + sb.append(measuments.get(i)); + } + return sb.append(']').toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,84 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.math.MathException; + +import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; + +import org.apache.log4j.Logger; + +public class Outlier +{ + private static Logger log = Logger.getLogger(Outlier.class); + + public interface Callback { + + void initialize(List<SQ> sqs) throws MathException; + + double eval(SQ sq); + + void iterationFinished( + double stdDev, + SQ outlier, + List<SQ> remaining); + + } // interface Callback + + public static void detectOutliers( + Callback callback, + List<SQ> sqs, + double stdDevFactor + ) + throws MathException + { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("stdDevFactor: " + stdDevFactor); + } + + List<SQ> data = new ArrayList<SQ>(sqs); + + while (data.size() > 2) { + + callback.initialize(data); + + StandardDeviation stdDev = new StandardDeviation(); + + double maxValue = -Double.MAX_VALUE; + int maxIndex = -1; + + for (int i = data.size()-1; i >= 0; --i) { + double value = Math.abs(callback.eval(data.get(i))); + stdDev.increment(value); + if (value > maxValue) { + maxValue = value; + maxIndex = i; + } + } + + double sd = stdDev.getResult(); + + double accepted = stdDevFactor * sd; + + if (debug) { + log.debug("std dev: " + stdDev); + log.debug("accepted: " + accepted); + log.debug("max value: " + maxValue); + } + + SQ outlier = maxValue > accepted + ? data.remove(maxIndex) + : null; + + callback.iterationFinished(sd, outlier, data); + + if (outlier == null) { + break; + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQ.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,41 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.io.Serializable; + + +public class SQ implements Serializable { + + protected double s; + protected double q; + + public SQ() { + } + + public SQ(double s, double q) { + this.s = s; + this.q = q; + } + + + public double getS() { + return s; + } + + public void setS(double s) { + this.s = s; + } + + + public double getQ() { + return q; + } + + public void setQ(double q) { + this.q = q; + } + + public boolean isValid() { + return !Double.isNaN(s) && !Double.isNaN(q); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,103 @@ +package de.intevation.flys.artifacts.model.sq; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet to show the curve in a sq relation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQCurveFacet extends DataFacet implements FacetTypes { + + private static final Logger log = Logger.getLogger(SQCurveFacet.class); + + + public static final String FUNCTION = "sq-pow"; + + + private int fractionIdx; + + + public SQCurveFacet() { + } + + + public SQCurveFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("SQCurveFacet.getData"); + + if (!(artifact instanceof FLYSArtifact)) { + return null; + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute( + context, ComputeType.ADVANCE, false); + + SQResult[] results = (SQResult[]) res.getData(); + SQFractionResult result = results[index].getFraction(fractionIdx); + + Parameters params = result.getParameters(); + + if (params == null) { + log.debug("no parameters found"); + return null; + } + + Function func = FunctionFactory.getInstance().getFunction(FUNCTION); + String[] paramNames = func.getParameterNames(); + + double [] coeffs = params.get(0, paramNames); + + if (log.isDebugEnabled()) { + for (int i = 0, N = paramNames.length; i < N; i++) { + log.debug("retrieved parameter " + paramNames[i] + + " = " + coeffs[i]); + } + } + + de.intevation.flys.artifacts.math.Function mf = + func.instantiate(coeffs); + + double [] extent = result.getQExtent(); + return new SQFunction(mf, extent[0], extent[1]); + } + + + @Override + public SQCurveFacet deepCopy() { + SQCurveFacet copy = new SQCurveFacet(); + copy.set(this); + + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,166 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.flys.artifacts.model.Parameters; + +import java.io.Serializable; + +import java.util.List; + +public class SQFractionResult +implements Serializable +{ + public static class Iteration + implements Serializable + { + protected Parameters parameters; + protected SQ [] measurements; + protected SQ [] outliers; + + public Iteration() { + } + + public Iteration( + Parameters parameters, + SQ [] measurements, + SQ [] outliers + ) { + this.parameters = parameters; + this.measurements = measurements; + this.outliers = outliers; + } + + public Parameters getParameters() { + return parameters; + } + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + public SQ [] getMeasurements() { + return measurements; + } + + public void setMeasurements(SQ [] measurements) { + this.measurements = measurements; + } + + public SQ [] getOutliers() { + return outliers; + } + + public void setOutliers(SQ [] outliers) { + this.outliers = outliers; + } + + public boolean isValid() { + return parameters != null + && measurements != null + && outliers != null; + } + + public int numOutliers() { + return outliers != null + ? outliers.length + : 0; + } + + public int numMeasurements() { + return measurements != null + ? measurements.length + : 0; + } + } // class Iteration + + protected SQ [] measurements; + protected List<Iteration> iterations; + + public SQFractionResult() { + } + + public SQFractionResult( + SQ [] measurements, + List<Iteration> iterations + ) { + this.measurements = measurements; + this.iterations = iterations; + } + + public SQ [] getMeasurements() { + return measurements; + } + + public void setMeasurements(SQ [] measurements) { + this.measurements = measurements; + } + + public List<Iteration> getIterations() { + return iterations; + } + + public void setIterations(List<Iteration> iterations) { + this.iterations = iterations; + } + + public double [] getQExtent() { + return getQExtent(new double[2]); + } + + public double [] getQExtent(double extent[]) { + extent[0] = Double.MAX_VALUE; + extent[1] = -Double.MIN_VALUE; + + for (SQ sq: measurements) { + double q = sq.getQ(); + if (q < extent[0]) extent[0] = q; + if (q > extent[1]) extent[1] = q; + } + + return extent; + } + + public int numIterations() { + return iterations != null ? iterations.size() : 0; + } + + public Parameters getParameters() { + return iterations != null && !iterations.isEmpty() + ? iterations.get(iterations.size()-1).getParameters() + : null; + } + + public SQ [] getOutliers(int index) { + return index >= 0 && index < iterations.size() + ? iterations.get(index).getOutliers() + : null; + } + + public Parameters getParameters(int index) { + return index >= 0 && index < iterations.size() + ? iterations.get(index).getParameters() + : null; + } + + public SQ [] getMeasurements(int index) { + return index >= 0 && index < iterations.size() + ? iterations.get(index).getMeasurements() + : null; + } + + public int totalNumOutliers() { + int sum = 0; + if (iterations != null) { + for (Iteration iteration: iterations) { + sum += iteration.numOutliers(); + } + } + return sum; + } + + public int numMeasurements() { + return measurements != null + ? measurements.length + : 0; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQFunction.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,36 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.flys.artifacts.math.Function; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQFunction { + + private Function function; + + private double minQ; + private double maxQ; + + + public SQFunction(Function function, double minQ, double maxQ) { + this.function = function; + this.minQ = minQ; + this.maxQ = maxQ; + } + + + public Function getFunction() { + return function; + } + + public double getMinQ() { + return minQ; + } + + public double getMaxQ() { + return maxQ; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model.sq; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + + +/** + * Facet to show the outliers in a sq relation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQMeasurementFacet extends DataFacet implements FacetTypes { + + private static final Logger log = Logger.getLogger(SQMeasurementFacet.class); + + + private int fractionIdx; + + + public SQMeasurementFacet() { + } + + + public SQMeasurementFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("SQMeasurementFacet.getData"); + + if (!(artifact instanceof FLYSArtifact)) { + return null; + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute( + context, ComputeType.ADVANCE, false); + + SQResult[] result = (SQResult[]) res.getData(); + SQFractionResult fResult = result[index].getFraction(fractionIdx); + + return fResult.getMeasurements(); + } + + + @Override + public SQMeasurementFacet deepCopy() { + SQMeasurementFacet copy = new SQMeasurementFacet(); + copy.set(this); + + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierCurveFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,102 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +public class SQOutlierCurveFacet +extends DataFacet +implements FacetTypes +{ + private static final Logger log = + Logger.getLogger(SQOutlierCurveFacet.class); + + public static final String FUNCTION = "sq-pow"; + + public static final int BITMASK_ITERATION = (1 << 16) - 1; + + private int fractionIdx; + + public SQOutlierCurveFacet() { + } + + public SQOutlierCurveFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("SQOutlierCurveFacet.getData"); + + if (!(artifact instanceof FLYSArtifact)) { + return null; + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute( + context, ComputeType.ADVANCE, false); + + int idx = this.index >> 16; + int iter = this.index & BITMASK_ITERATION; + + SQResult[] results = (SQResult[]) res.getData(); + SQFractionResult result = results[idx].getFraction(fractionIdx); + + Parameters params = result.getParameters(iter); + + if (params == null) { + return null; + } + + Function func = FunctionFactory.getInstance().getFunction(FUNCTION); + String [] paramNames = func.getParameterNames(); + + double [] coeffs = params.get(0, paramNames); + + if (log.isDebugEnabled()) { + for (int i = 0; i < paramNames.length; i++) { + log.debug("retrieved parameter " + paramNames[i] + + " = " + coeffs[i]); + } + } + + de.intevation.flys.artifacts.math.Function mf = + func.instantiate(coeffs); + + double [] extent = result.getQExtent(); + return new SQFunction(mf, extent[0], extent[1]); + } + + @Override + public Facet deepCopy() { + SQOutlierCurveFacet copy = new SQOutlierCurveFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +/** + * Facet to show the curve in a sq relation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQOutlierFacet extends DataFacet implements FacetTypes { + + private static final Logger log = Logger.getLogger(SQOutlierFacet.class); + + public static final int BITMASK_ITERATION = (1 << 16) - 1; + + private int fractionIdx; + + public SQOutlierFacet() { + } + + public SQOutlierFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("SQOutlierFacet.getData"); + + if (!(artifact instanceof FLYSArtifact)) { + return null; + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute( + context, ComputeType.ADVANCE, false); + + int idx = this.index >> 16; + int iter = this.index & BITMASK_ITERATION; + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("Fetch data for index : " + this.index); + log.debug(" > index: " + idx); + log.debug(" > fraction: " + fractionIdx); + log.debug(" > iteration: " + iter); + } + + SQResult[] result = (SQResult[]) res.getData(); + SQFractionResult fResult = result[idx].getFraction(fractionIdx); + + if (fResult == null) { + log.warn("No SQFractionResult at " + idx + "|" + fractionIdx); + return null; + } + + SQ [] outliers = fResult.getOutliers(iter); + + if (debug) { + int num = outliers != null ? outliers.length : 0; + log.debug("Found " + num + " outliers for iteration " + iter); + } + + return outliers; + } + + + @Override + public SQOutlierFacet deepCopy() { + SQOutlierFacet copy = new SQOutlierFacet(); + copy.set(this); + + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierMeasurementFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +import org.apache.log4j.Logger; + +public class SQOutlierMeasurementFacet +extends DataFacet +implements FacetTypes +{ + private static final Logger log = + Logger.getLogger(SQOutlierMeasurementFacet.class); + + private int fractionIdx; + + public static final int BITMASK_ITERATION = (1 << 16) - 1; + + public SQOutlierMeasurementFacet() { + } + + public SQOutlierMeasurementFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("SQOutlierMeasurementFacet.getData"); + + if (!(artifact instanceof FLYSArtifact)) { + return null; + } + + FLYSArtifact flys = (FLYSArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute( + context, ComputeType.ADVANCE, false); + + int idx = this.index >> 16; + int iter = this.index & BITMASK_ITERATION; + + SQResult[] result = (SQResult[]) res.getData(); + SQFractionResult fResult = result[idx].getFraction(fractionIdx); + + return fResult.getMeasurements(iter); + } + + @Override + public Facet deepCopy() { + SQOutlierMeasurementFacet copy = new SQOutlierMeasurementFacet(); + copy.set(this); + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.model.sq; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + +public class SQOverviewFacet +extends DataFacet +implements FacetTypes +{ + private static final Logger logger = Logger.getLogger(SQOverviewFacet.class); + + protected int fractionIdx; + + public SQOverviewFacet() { + } + + public SQOverviewFacet( + int idx, + int fractionIdx, + String name, + String description, + String hash, + String stateId + ) { + super(idx, name, description, ComputeType.ADVANCE, hash, stateId); + this.fractionIdx = fractionIdx; + } + + + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("SQOverviewFacet.getData"); + + switch(fractionIdx) { + case 0: return "sq_relation_a"; + case 1: return "sq_relation_b"; + case 2: return "sq_relation_c"; + case 3: return "sq_relation_d"; + case 4: return "sq_relation_e"; + case 5: return "sq_relation_f"; + default: return null; + } + } + + + @Override + public SQOverviewFacet deepCopy() { + SQOverviewFacet copy = new SQOverviewFacet(); + copy.set(this); + + return copy; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,189 @@ +package de.intevation.flys.artifacts.model.sq; + +import de.intevation.flys.artifacts.access.SQRelationAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.backend.SedDBSessionHolder; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class SQRelationCalculation extends Calculation { + + private static final Logger log = + Logger.getLogger(SQRelationCalculation.class); + + public static final String SQ_FUNCTION_NAME = "sq-pow"; + + protected String river; + protected double location; + protected DateRange period; + protected double outliers; + + public SQRelationCalculation() { + } + + public SQRelationCalculation(SQRelationAccess access) { + + String river = access.getRiver(); + Double location = access.getLocation(); + DateRange period = access.getPeriod(); + Double outliers = access.getOutliers(); + + //river = "Rhein"; + + if (river == null) { + // TODO: i18n + addProblem("sq.missing.river"); + } + + if (location == null) { + // TODO: i18n + addProblem("sq.missing.location"); + } + + if (period == null) { + // TODO: i18n + addProblem("sq.missing.periods"); + } + + if (outliers == null) { + // TODO: i18n + addProblem("sq.missing.outliers"); + } + + if (!hasProblems()) { + this.river = river; + this.location = location; + this.period = period; + this.outliers = outliers; + } + } + + + public CalculationResult calculate() { + log.debug("SQRelationCalculation.calculate"); + + if (hasProblems()) { + return new CalculationResult(this); + } + + SedDBSessionHolder.acquire(); + try { + return internalCalculate(); + } + finally { + SedDBSessionHolder.release(); + } + } + + protected CalculationResult internalCalculate() { + + boolean debug = log.isDebugEnabled(); + + Function function = FunctionFactory + .getInstance() + .getFunction(SQ_FUNCTION_NAME); + + if (function == null) { + log.error("No '" + SQ_FUNCTION_NAME + "' function found."); + // TODO: i18n + addProblem("sq.missing.sq.function"); + } + + String [] parameterNames = function.getParameterNames(); + + Measurements measurements = + MeasurementFactory.getMeasurements(river, location, period); + + SQFractionResult [] fractionResults = + new SQFractionResult[SQResult.NUMBER_FRACTIONS]; + + for (int i = 0; i < fractionResults.length; ++i) { + List<SQ> sqs = measurements.getSQs(i); + + SQFractionResult fractionResult; + + List<SQFractionResult.Iteration> iterations = + doFitting(function, sqs); + + if (iterations == null) { + // TODO: i18n + addProblem("sq.fitting.failed." + i); + fractionResult = new SQFractionResult(); + } + else { + fractionResult = new SQFractionResult( + sqs.toArray(new SQ[sqs.size()]), + iterations); + } + + fractionResults[i] = fractionResult; + } + + return new CalculationResult( + new SQResult[] { new SQResult(location, fractionResults) }, + this); + } + + protected List<SQFractionResult.Iteration> doFitting( + final Function function, + List<SQ> sqs + ) { + final List<SQFractionResult.Iteration> iterations = + new ArrayList<SQFractionResult.Iteration>(); + + boolean success = new Fitting(function, outliers).fit( + sqs, + new Fitting.Callback() { + @Override + public void afterIteration( + double [] coeffs, + SQ [] measurements, + SQ [] outliers, + double standardDeviation, + double chiSqr + ) { + Parameters parameters = createParameters( + function.getParameterNames(), + coeffs, + standardDeviation, + chiSqr); + iterations.add(new SQFractionResult.Iteration( + parameters, + measurements, + outliers)); + } + }); + + return success ? iterations : null; + } + + public static final Parameters createParameters( + String [] names, + double [] values, + double standardDeviation, + double chiSqr + ) { + String [] columns = new String[names.length + 2]; + columns[0] = "chi_sqr"; + columns[1] = "std_dev"; + System.arraycopy(names, 0, columns, 2, names.length); + Parameters parameters = new Parameters(columns); + int row = parameters.newRow(); + parameters.set(row, names, values); + parameters.set(row, "chi_sqr", chiSqr); + parameters.set(row, "std_dev", standardDeviation); + return parameters; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,60 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.io.Serializable; + + + +public class SQResult implements Serializable { + + public static final int NUMBER_FRACTIONS = 6; + + public static final int FRACTION_A = 0; + public static final int FRACTION_B = 1; + public static final int FRACTION_C = 2; + public static final int FRACTION_D = 3; + public static final int FRACTION_E = 4; + public static final int FRACTION_F = 5; + + protected double km; + protected SQFractionResult[] fractions; + + public SQResult() { + this(0d, new SQFractionResult[NUMBER_FRACTIONS]); + } + + public SQResult(double km, SQFractionResult [] fractions) { + this.km = km; + this.fractions = fractions; + } + + public SQFractionResult getFraction(int idx) { + return idx >= 0 && idx < fractions.length + ? fractions[idx] + : null; + } + + public void setFraction(int idx, SQFractionResult fraction) { + if (idx >= 0 && idx < fractions.length) { + this.fractions[idx] = fraction; + } + } + + public static final String [] FRACTION_NAMES = { + "A", "B", "C", "D", "E", "F" + }; + + public String getFractionName(int idx) { + return idx >= 0 && idx < FRACTION_NAMES.length + ? FRACTION_NAMES[idx] + : ""; + } + + public double getKm() { + return km; + } + + public void setKm(double km) { + this.km = km; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Sieve.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,52 @@ +package de.intevation.flys.artifacts.model.sq; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class Sieve +{ + public double [] fractionSizes; + + protected List<List<SQ>> fractions; + + public Sieve() { + } + + public Sieve(double [] fractionSizes) { + this.fractionSizes = fractionSizes; + fractions = new ArrayList<List<SQ>>(fractionSizes.length+1); + for (int i = fractionSizes.length; i >= 0; --i) { + fractions.add(new ArrayList<SQ>()); + } + } + + public void sieve(Iterator<SQ> sqs) { + OUTER: while (sqs.hasNext()) { + SQ sq = sqs.next(); + double q = sq.getQ(); + for (int i = 0; i < fractionSizes.length; ++i) { + if (q < fractionSizes[i]) { + fractions.get(i).add(sq); + continue OUTER; + } + } + fractions.get(fractions.size()-1).add(sq); + } + } + + public int numFractions() { + return fractions.size(); + } + + public List<SQ> getFraction(int idx) { + return fractions.get(idx); + } + + public void reset() { + for (List<SQ> fraction: fractions) { + fraction.clear(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/resources/Resources.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,179 @@ +package de.intevation.flys.artifacts.resources; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallMeta; + +/** + * This class provides methods for i18n. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class Resources { + + /** The logger that is used in this class.*/ + private static Logger logger = Logger.getLogger(Resources.class); + + /** The singleton instance.*/ + private static Resources INSTANCE; + + /** The locales supported by this server.*/ + protected Locale[] locales; + + /** + * No instance of this class is necessary. + */ + private Resources() { + } + + + /** + * Returns the locales supported by this server. + * + * @return the supported locales. + */ + public synchronized Locale [] getLocales() { + if (locales == null) { + readLocales(); + } + + return locales; + } + + + /** + * Read the locales configured for this server. + */ + protected void readLocales() { + // TODO IMPLEMENT ME + + locales = new Locale[2]; + locales[0] = Locale.GERMANY; + locales[1] = Locale.ENGLISH; + } + + + private static synchronized void ensureInstance() { + if (INSTANCE == null) { + INSTANCE = new Resources(); + } + } + + + public static Locale getLocale(CallMeta meta) { + ensureInstance(); + + Locale[] locales = INSTANCE.getLocales(); + return meta.getPreferredLocale(locales); + } + + + /** + * This method returns the translated value for <i>key</i> or <i>def</i> if + * <i>key</i> is not existing in the resource bundle. + * + * @param meta The CallMeta object of the request that contains the + * preferred locale. + * @param key The key that should be translated. + * @param def A default value that is returned, if <i>key</i> was not found. + * + * @return the translated message. + */ + public static String getMsg(CallMeta meta, String key, String def) { + ensureInstance(); + + Locale[] locales = INSTANCE.getLocales(); + Locale locale = meta.getPreferredLocale(locales); + + return getMsg(locale, key, def); + } + + public static String getMsg( + CallMeta meta, + String key, + Object[] args + ) { + return getMsg(meta, key, key, args); + } + + /** + * Returns a translated message based on a template specified by <i>key</i> + * that has necessary values to be filled in. + * + * @param meta The CallMeta object. + * @param key The key of the template in the resource bundle. + * @param def the default value if no template was found with <i>key</i>. + * @param args The arguments that are necessary for the template. + * + * @return a translated string. + */ + public static String getMsg( + CallMeta meta, + String key, + String def, + Object[] args) + { + String template = getMsg(meta, key, (String)null); + + if (template == null) { + return def; + } + + return format(meta, template, args); + } + + public static String format( + CallMeta meta, + String key, + String def, + Object ... args + ) { + String template = getMsg(meta, key, (String)null); + + if (template == null) { + template = def; + } + + return format(meta, template, args); + } + + /** + * Formats the given template using the arguments with respect of the + * appropriate locale given by the CallMeta instance. + */ + public static String format(CallMeta meta, String templ, Object ... args) { + Locale locale = getLocale(meta); + MessageFormat mf = new MessageFormat(templ, locale); + + return mf.format(args, new StringBuffer(), null).toString(); + } + + /** + * This method returns the translated value for <i>key</i> or <i>def</i> if + * <i>key</i> is not existing in the resource bundle. + * + * @param locale The locale. + * @param key The key that should be translated. + * @param def A default value that is returned, if <i>key</i> was not found. + * + * @return the translated message. + */ + public static String getMsg(Locale locale, String key, String def) { + ResourceBundle bundle = ResourceBundle.getBundle("messages", locale); + + try { + return bundle.getString(key); + } + catch (MissingResourceException mre) { + logger.warn("No message found for key: " + key); + + return def; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,305 @@ +package de.intevation.flys.artifacts.services; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.DateAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import de.intevation.artifactdatabase.DefaultService; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.Service; +import de.intevation.flys.artifacts.model.minfo.BedOverview; +import de.intevation.flys.artifacts.model.minfo.BedOverviewFactory; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.backend.SedDBSessionHolder; +import de.intevation.flys.utils.KMIndex; + +public class BedKMChartService extends DefaultService { + + /** + * + */ + private static final long serialVersionUID = -4946194087923870485L; + + private static final Logger log = + Logger.getLogger(BedKMChartService.class); + + public static final int DEFAULT_WIDTH = 240; + public static final int DEFAULT_HEIGHT = 180; + + public static final String I18N_CHART_LABEL = + "bed.km.chart.label"; + + public static final String DEFAULT_CHART_LABEL = + "Measuring Points"; + + public static final String I18N_CHART_TITLE = + "bed.km.chart.title"; + + public static final String DEFAULT_CHART_TITLE = + "Measuring points"; + + public static final String I18N_KM_AXIS = + "bed.km.chart.km.axis"; + + public static final String DEFAULT_KM_AXIS = + "km"; + + public static final String I18N_DATE_AXIS = + "bed.km.chart.date.axis"; + + public static final String DEFAULT_DATE_AXIS = + "Date"; + + public static final String DEFAULT_FORMAT = "png"; + + // TODO: Load fancy image from resources. + public static final byte [] EMPTY = { + (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, + (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d, + (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b, + (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47, + (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce, + (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48, + (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00, + (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74, + (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07, + (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10, + (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77, + (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45, + (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f, + (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e, + (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc, + (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44, + (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7, + (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00, + (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44, + (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82 + }; + + private static final Output empty() { + return new Output(EMPTY, "image/png"); + } + + @Override + public Service.Output process( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("SQKMChartService.process"); + + SedDBSessionHolder.acquire(); + try { + return doProcess(data, globalContext, callMeta); + } + finally { + SedDBSessionHolder.HOLDER.get().close(); + SedDBSessionHolder.release(); + } + } + + protected Service.Output doProcess( + Document input, + GlobalContext globalContext, + CallMeta callMeta + ) { + String river = getRiverName(input); + Dimension extent = getExtent(input); + String format = getFormat(input); + + if (river == null) { + log.warn("River invalid."); + return empty(); + } + + BedOverview overview = BedOverviewFactory.getOverview(river); + + if (overview == null) { + log.warn("No overview found for river '" + river + "'"); + return empty(); + } + + KMIndex<List<Date>> entries = overview.filter(BedOverview.ACCEPT); + + JFreeChart chart = createChart(entries, river, callMeta); + + return encode(chart, extent, format); + } + + protected static Output encode( + JFreeChart chart, + Dimension extent, + String format + ) { + BufferedImage image = chart.createBufferedImage( + extent.width, extent.height, + Transparency.BITMASK, + null); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + try { + ImageIO.write(image, format, out); + } + catch (IOException ioe) { + log.warn("writing image failed", ioe); + return empty(); + } + + return new Output(out.toByteArray(), "image/" + format); + } + + protected static JFreeChart createChart( + KMIndex<List<Date>> entries, + String river, + CallMeta callMeta + ) { + + XYSeriesCollection dataset = new XYSeriesCollection(); + String key = Resources.format( + callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river); + + XYSeries series = new XYSeries(key); + for (KMIndex.Entry<List<Date>> e: entries) { + double km = e.getKm(); + List<Date> ds = e.getValue(); + for (Date d: ds) { + series.add(km, d.getTime()); + } + } + + dataset.addSeries(series); + String title = Resources.format( + callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river); + + String kmAxis = Resources.getMsg( + callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS); + + String dateAxis = Resources.getMsg( + callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS); + + JFreeChart chart = ChartFactory.createXYLineChart( + title, + kmAxis, + dateAxis, + null, + PlotOrientation.VERTICAL, + true, + true, + false); + + XYPlot plot = (XYPlot)chart.getPlot(); + + DateAxis dA = new DateAxis(); + plot.setRangeAxis(dA); + plot.setDataset(0, dataset); + + chart.setBackgroundPaint(Color.white); + plot.setBackgroundPaint(Color.white); + plot.setDomainGridlinePaint(Color.gray); + plot.setRangeGridlinePaint(Color.gray); + plot.setDomainGridlinesVisible(true); + plot.setRangeGridlinesVisible(true); + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer(); + + renderer.setSeriesPaint(0, Color.gray); + renderer.setSeriesLinesVisible(0, false); + renderer.setSeriesShapesVisible(0, true); + renderer.setDrawOutlines(true); + return chart; + } + + + protected static String getRiverName(Document input) { + NodeList rivers = input.getElementsByTagName("river"); + + if (rivers.getLength() == 0) { + return null; + } + + String river = ((Element)rivers.item(0)).getAttribute("name"); + + return river.length() > 0 ? river : null; + } + + protected static Dimension getExtent(Document input) { + + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + + NodeList extents = input.getElementsByTagName("extent"); + + if (extents.getLength() > 0) { + Element element = (Element)extents.item(0); + String w = element.getAttribute("width"); + String h = element.getAttribute("height"); + + try { + width = Math.max(1, Integer.parseInt(w)); + } + catch (NumberFormatException nfe) { + log.warn("width '" + w + "' is not a valid."); + } + + try { + height = Math.max(1, Integer.parseInt(h)); + } + catch (NumberFormatException nfe) { + log.warn("height '" + h + "' is not a valid"); + } + } + + return new Dimension(width, height); + } + + protected static String getFormat(Document input) { + String format = DEFAULT_FORMAT; + + NodeList formats = input.getElementsByTagName("format"); + + if (formats.getLength() > 0) { + String type = ((Element)formats.item(0)).getAttribute("type"); + if (type.length() > 0) { + format = type; + } + } + + return format; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,305 @@ +package de.intevation.flys.artifacts.services; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.DateAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import de.intevation.artifactdatabase.DefaultService; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.Service; +import de.intevation.flys.artifacts.model.minfo.BedloadOverview; +import de.intevation.flys.artifacts.model.minfo.BedloadOverviewFactory; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.backend.SedDBSessionHolder; +import de.intevation.flys.utils.KMIndex; + +public class BedloadKMChartService extends DefaultService { + + /** + * + */ + private static final long serialVersionUID = 4156704841305086495L; + + private static final Logger log = + Logger.getLogger(BedloadKMChartService.class); + + public static final int DEFAULT_WIDTH = 240; + public static final int DEFAULT_HEIGHT = 180; + + public static final String I18N_CHART_LABEL = + "bedload.km.chart.label"; + + public static final String DEFAULT_CHART_LABEL = + "Measuring Points"; + + public static final String I18N_CHART_TITLE = + "bedload.km.chart.title"; + + public static final String DEFAULT_CHART_TITLE = + "Measuring points"; + + public static final String I18N_KM_AXIS = + "bedload.km.chart.km.axis"; + + public static final String DEFAULT_KM_AXIS = + "km"; + + public static final String I18N_DATE_AXIS = + "bedload.km.chart.date.axis"; + + public static final String DEFAULT_DATE_AXIS = + "Date"; + + public static final String DEFAULT_FORMAT = "png"; + + // TODO: Load fancy image from resources. + public static final byte [] EMPTY = { + (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, + (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d, + (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b, + (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47, + (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce, + (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48, + (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00, + (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74, + (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07, + (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10, + (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77, + (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45, + (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f, + (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e, + (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc, + (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44, + (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7, + (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00, + (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44, + (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82 + }; + + private static final Output empty() { + return new Output(EMPTY, "image/png"); + } + + @Override + public Service.Output process( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("SQKMChartService.process"); + + SedDBSessionHolder.acquire(); + try { + return doProcess(data, globalContext, callMeta); + } + finally { + SedDBSessionHolder.HOLDER.get().close(); + SedDBSessionHolder.release(); + } + } + + protected Service.Output doProcess( + Document input, + GlobalContext globalContext, + CallMeta callMeta + ) { + String river = getRiverName(input); + Dimension extent = getExtent(input); + String format = getFormat(input); + + if (river == null) { + log.warn("River invalid."); + return empty(); + } + + BedloadOverview overview = BedloadOverviewFactory.getOverview(river); + + if (overview == null) { + log.warn("No overview found for river '" + river + "'"); + return empty(); + } + + KMIndex<List<Date>> entries = overview.filter(BedloadOverview.ACCEPT); + + JFreeChart chart = createChart(entries, river, callMeta); + + return encode(chart, extent, format); + } + + protected static Output encode( + JFreeChart chart, + Dimension extent, + String format + ) { + BufferedImage image = chart.createBufferedImage( + extent.width, extent.height, + Transparency.BITMASK, + null); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + try { + ImageIO.write(image, format, out); + } + catch (IOException ioe) { + log.warn("writing image failed", ioe); + return empty(); + } + + return new Output(out.toByteArray(), "image/" + format); + } + + protected static JFreeChart createChart( + KMIndex<List<Date>> entries, + String river, + CallMeta callMeta + ) { + + XYSeriesCollection dataset = new XYSeriesCollection(); + String key = Resources.format( + callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river); + + XYSeries series = new XYSeries(key); + for (KMIndex.Entry<List<Date>> e: entries) { + double km = e.getKm(); + List<Date> ds = e.getValue(); + for (Date d: ds) { + series.add(km, d.getTime()); + } + } + + dataset.addSeries(series); + String title = Resources.format( + callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river); + + String kmAxis = Resources.getMsg( + callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS); + + String dateAxis = Resources.getMsg( + callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS); + + JFreeChart chart = ChartFactory.createXYLineChart( + title, + kmAxis, + dateAxis, + null, + PlotOrientation.VERTICAL, + true, + true, + false); + + XYPlot plot = (XYPlot)chart.getPlot(); + + DateAxis dA = new DateAxis(); + plot.setRangeAxis(dA); + plot.setDataset(0, dataset); + + chart.setBackgroundPaint(Color.white); + plot.setBackgroundPaint(Color.white); + plot.setDomainGridlinePaint(Color.gray); + plot.setRangeGridlinePaint(Color.gray); + plot.setDomainGridlinesVisible(true); + plot.setRangeGridlinesVisible(true); + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer(); + + renderer.setSeriesPaint(0, Color.gray); + renderer.setSeriesLinesVisible(0, false); + renderer.setSeriesShapesVisible(0, true); + renderer.setDrawOutlines(true); + return chart; + } + + + protected static String getRiverName(Document input) { + NodeList rivers = input.getElementsByTagName("river"); + + if (rivers.getLength() == 0) { + return null; + } + + String river = ((Element)rivers.item(0)).getAttribute("name"); + + return river.length() > 0 ? river : null; + } + + protected static Dimension getExtent(Document input) { + + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + + NodeList extents = input.getElementsByTagName("extent"); + + if (extents.getLength() > 0) { + Element element = (Element)extents.item(0); + String w = element.getAttribute("width"); + String h = element.getAttribute("height"); + + try { + width = Math.max(1, Integer.parseInt(w)); + } + catch (NumberFormatException nfe) { + log.warn("width '" + w + "' is not a valid."); + } + + try { + height = Math.max(1, Integer.parseInt(h)); + } + catch (NumberFormatException nfe) { + log.warn("height '" + h + "' is not a valid"); + } + } + + return new Dimension(width, height); + } + + protected static String getFormat(Document input) { + String format = DEFAULT_FORMAT; + + NodeList formats = input.getElementsByTagName("format"); + + if (formats.getLength() > 0) { + String type = ((Element)formats.item(0)).getAttribute("type"); + if (type.length() > 0) { + format = type; + } + } + + return format; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,54 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.XMLService; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import net.sf.ehcache.Cache; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class CacheInvalidationService +extends XMLService +{ + @Override + public Document processXML( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + Document result = XMLUtils.newDocument(); + + Element all = result.createElement("caches"); + + NodeList caches = data.getElementsByTagName("cache"); + + for (int i = 0, C = caches.getLength(); i < C; ++i) { + Element c = (Element)caches.item(i); + String name = c.getAttribute("name"); + Element e = result.createElement("cache"); + e.setAttribute("name", name); + Cache cache = CacheFactory.getCache(name); + if (cache != null) { + cache.removeAll(); + e.setTextContent("All elements removed."); + } + else { + e.setTextContent("Error: Cache not found."); + } + all.appendChild(e); + } + + result.appendChild(all); + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,242 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import de.intevation.flys.model.CrossSection; +import de.intevation.flys.model.CrossSectionLine; + +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; + +import java.util.concurrent.ConcurrentSkipListMap; + +import net.sf.ehcache.Cache; + +import org.apache.log4j.Logger; + +import org.hibernate.Query; +import org.hibernate.Session; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +/** + * Service to find the next/previous km (measurement) of cross sections. + * Looking at the query for a single cross-section id at a single km, the + * service does the following: + * + * It returns the km itself if a measurement at that km was found and + * the N nearest other measurement points in both directions. + * + * That means, you can pass N=0 to find out whether a measurement at given km + * exists. + * + * If less than N neighbours exist in one direction, less are delivered + * (e.g. given measurements at [0,2,3,4,5,7,8,9] a query for km=8, N=3 will + * result in [4,5,7,8,9]). + */ +public class CrossSectionKMService +extends FLYSService +{ + private static Logger logger = + Logger.getLogger(CrossSectionKMService.class); + + public static final String CACHE_NAME = "cross-section-kms"; + + + /** Trivial constructor. */ + public CrossSectionKMService() { + } + + + /** + * @param data + */ + @Override + public Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("CrossSectionKMService.doProcess"); + + NodeList crossSectionNodes = + data.getElementsByTagName("art:cross-section"); + + Document document = XMLUtils.newDocument(); + + Element all = document.createElement("cross-sections"); + + for (int i = 0, CS = crossSectionNodes.getLength(); i < CS; ++i) { + Element crossSectionElement = (Element)crossSectionNodes.item(i); + + String idString = crossSectionElement.getAttribute("id"); + String kmString = crossSectionElement.getAttribute("km"); + String neighborsString = crossSectionElement.getAttribute("n"); + + if (idString.length() == 0 || kmString.length() == 0) { + logger.debug("missing attributes in cross-section element"); + continue; + } + + double km; + Integer crossSectionId; + int N = 2; + + try { + km = Double.parseDouble(kmString); + crossSectionId = Integer.valueOf(idString); + + if (neighborsString.length() > 0) { + N = Integer.parseInt(neighborsString); + } + } + catch (NumberFormatException nfe) { + logger.debug("converting number failed", nfe); + continue; + } + + NavigableMap<Double, Integer> map = getKms(crossSectionId); + + if (map == null) { + logger.debug("cannot find cross section " + crossSectionId); + continue; + } + + Deque<Map.Entry<Double, Integer>> result = + nearestNeighbors(map, km, N); + + if (!result.isEmpty()) { + Element csE = document.createElement("cross-section"); + csE.setAttribute("id", idString); + for (Map.Entry<Double, Integer> entry: result) { + Element lineE = document.createElement("line"); + lineE.setAttribute( + "line-id", String.valueOf(entry.getValue())); + lineE.setAttribute( + "km", String.valueOf(entry.getKey())); + csE.appendChild(lineE); + } + all.appendChild(csE); + } + } + + document.appendChild(all); + + return document; + } + + public static NavigableMap<Double, Integer> getKms(int crossSectionId) { + + Cache cache = CacheFactory.getCache(CACHE_NAME); + + if (cache == null) { + return getUncached(crossSectionId); + } + + NavigableMap<Double, Integer> map; + + net.sf.ehcache.Element element = cache.get(crossSectionId); + if (element == null) { + map = getUncached(crossSectionId); + if (map != null) { + element = new net.sf.ehcache.Element( + crossSectionId, map); + cache.put(element); + } + } + else { + map = (NavigableMap<Double, Integer>)element.getValue(); + } + + return map; + } + + + /** + * @param km the kilometer from which to start searching for other + * measurements + * @param N number of neighboring measurements to find. + */ + public static Deque<Map.Entry<Double, Integer>> nearestNeighbors( + NavigableMap<Double, Integer> map, + double km, + int N + ) { + Deque<Map.Entry<Double, Integer>> result = + new ArrayDeque<Map.Entry<Double, Integer>>(2*N); + + Integer v = map.get(km); + + if (v != null) { + result.add(new AbstractMap.SimpleEntry<Double, Integer>(km, v)); + } + + int i = 0; + for (Map.Entry<Double, Integer> entry: + map.headMap(km, false).descendingMap().entrySet()) { + if (i++ >= N) { + break; + } + result.addFirst(entry); + } + + i = 0; + for (Map.Entry<Double, Integer> entry: + map.tailMap(km, false).entrySet()) { + if (i++ >= N) { + break; + } + result.addLast(entry); + } + + return result; + } + + + /** + * @param crossSectionId id of queried cross-section (in db). + * @return Mapping from kilometer to db-id. + */ + public static NavigableMap<Double, Integer> getUncached( + Integer crossSectionId + ) { + NavigableMap<Double, Integer> result = + new ConcurrentSkipListMap<Double, Integer>(); + + Session session = SessionHolder.HOLDER.get(); + Query query = session.createQuery( + "from CrossSection where id=:id"); + query.setParameter("id", crossSectionId); + + List<CrossSection> crossSections = query.list(); + if (crossSections.isEmpty()) { + return null; + } + + CrossSection crossSection = crossSections.get(0); + List<CrossSectionLine> lines = crossSection.getLines(); + + for (CrossSectionLine line: lines) { + Double km = line.getKm().doubleValue(); + Integer id = line.getId(); + result.put(km, id); + } + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,128 @@ +package de.intevation.flys.artifacts.services; + +import java.util.List; +import java.util.Date; +import java.util.Calendar; +import java.util.GregorianCalendar; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.TimeInterval; + +/** + * This service provides information about discharges at a defined gauge. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class DischargeInfoService extends FLYSService { + + /** The logger used in this service. */ + private static Logger logger = Logger.getLogger(DischargeInfoService.class); + + public static final String GAUGE_XPATH = "/art:gauge/text()"; + + public DischargeInfoService() { + } + + + @Override + public Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("DischargeInfoService.process"); + + String gaugeNumber = XMLUtils.xpathString( + data, GAUGE_XPATH, ArtifactNamespaceContext.INSTANCE); + + if(gaugeNumber == null || + (gaugeNumber = gaugeNumber.trim()).length() == 0) { + logger.warn("No gauge specified. Cannot return discharge info."); + return XMLUtils.newDocument(); + } + + logger.debug("Getting discharge for gauge: " + gaugeNumber); + + long gn; + try { + gn = Long.parseLong(gaugeNumber); + } + catch (NumberFormatException nfe) { + logger.warn("Invalid gauge number. Cannot return discharg info."); + return XMLUtils.newDocument(); + } + + Gauge gauge = Gauge.getGaugeByOfficialNumber(gn); + + logger.debug("Found gauge: " + gauge.getName()); + + return buildDocument(gauge); + } + + + protected Document buildDocument(Gauge gauge) { + Document result = XMLUtils.newDocument(); + + List<DischargeTable> tables =gauge.getDischargeTables(); + + Element all = result.createElement("discharges"); + for (DischargeTable dt: tables) { + if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE) { + continue; + } + + Element discharge = result.createElement("discharge"); + discharge.setAttribute("description", dt.getDescription()); + + // Get time interval. + TimeInterval ti = dt.getTimeInterval(); + + if (ti == null) { + logger.warn("DischargeTable has no TimeInterval set!"); + continue; + } + + Date startTime = ti.getStartTime(); + Date stopTime = ti.getStopTime(); + + // Get the year for start end end date. + int startYear; + int stopYear; + Calendar c = new GregorianCalendar(); + if (startTime != null) { + c.setTime(startTime); + startYear = c.get(Calendar.YEAR); + } + else { + startYear = -1; + } + if (stopTime != null) { + c.setTime(stopTime); + stopYear = c.get(Calendar.YEAR); + } + else { + stopYear = -1; + } + + discharge.setAttribute("start", String.valueOf(startYear)); + discharge.setAttribute("end", String.valueOf(stopYear)); + + all.appendChild(discharge); + } + result.appendChild(all); + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,141 @@ +package de.intevation.flys.artifacts.services; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.model.FastAnnotations; + +import de.intevation.flys.artifacts.model.LocationProvider; + + +/** + * This service provides information about distances of a specified river. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DistanceInfoService extends FLYSService { + + /** The logger used in this service. */ + private static Logger logger = Logger.getLogger(DistanceInfoService.class); + + public static final String RIVER_XPATH = "/art:river/text()"; + + public static final String FILTER_XPATH = "/art:river/art:filter/text()"; + + + /** + * The default constructor. + */ + public DistanceInfoService() { + } + + + @Override + public Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("DistanceInfoService.process"); + + String river = XMLUtils.xpathString( + data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE); + + String filterName = XMLUtils.xpathString( + data, FILTER_XPATH, ArtifactNamespaceContext.INSTANCE); + + if (river == null || (river = river.trim()).length() == 0) { + logger.warn("No river specified. Cannot return distance info!"); + return XMLUtils.newDocument(); + } + + logger.debug("Search distances for river: " + river); + + FastAnnotations fas = LocationProvider.getAnnotations(river); + + FastAnnotations.Filter filter = selectFilter(filterName); + + return buildDocument(fas.filter(filter)); + } + + protected Document buildDocument( + Iterator<FastAnnotations.Annotation> iter + ) { + Document result = XMLUtils.newDocument(); + + Element all = result.createElement("distances"); + + while (iter.hasNext()) { + all.appendChild(buildNode(result, iter.next())); + } + + result.appendChild(all); + + return result; + } + + protected static FastAnnotations.Filter selectFilter(String name) { + + if (name != null) { + if ("locations".equals(name)) return FastAnnotations.IS_POINT; + if ("distances".equals(name)) return FastAnnotations.IS_RANGE; + if ("measuringpoint".equals(name)) + return new FastAnnotations.NameFilter("Messstelle"); + } + + return FastAnnotations.ALL; + } + + /** + * Builds an Element for a distance info. + * + * @param an The Annotation that provides information about the distance. + * + * @return an Element that contains information about a distance. + */ + protected static Element buildNode( + Document document, + FastAnnotations.Annotation an + ) { + Element distance = document.createElement("distance"); + + distance.setAttribute("description", an.getPosition()); + + String riverSide = an.getAttribute(); + + if (riverSide != null && riverSide.length() > 0) { + distance.setAttribute("riverside", riverSide); + } + + distance.setAttribute("from", String.valueOf(an.getA())); + + double b = an.getB(); + double bottom = an.getBottom(); + double top = an.getTop(); + + if (!Double.isNaN(b)) { + distance.setAttribute("to", String.valueOf(b)); + } + + if (!Double.isNaN(bottom)) { + distance.setAttribute("bottom", String.valueOf(bottom)); + } + + if (!Double.isNaN(top)) { + distance.setAttribute("top", String.valueOf(top)); + } + + return distance; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FLYSService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,59 @@ +package de.intevation.flys.artifacts.services; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import org.hibernate.Session; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifactdatabase.XMLService; + +import de.intevation.flys.backend.SessionHolder; + + +public abstract class FLYSService extends XMLService { + + private static final Logger logger = Logger.getLogger(FLYSService.class); + + + @Override + public Document processXML( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + init(); + + try { + return doProcess(data, globalContext, callMeta); + } + finally { + shutdown(); + } + } + + + protected abstract Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta); + + + protected void init() { + logger.debug("init"); + SessionHolder.acquire(); + } + + + protected void shutdown() { + logger.debug("shutdown"); + Session session = SessionHolder.HOLDER.get(); + session.close(); + + SessionHolder.release(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,104 @@ +package de.intevation.flys.artifacts.services; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.apache.log4j.Logger; + +import org.apache.commons.codec.binary.Base64; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.utils.FileTools; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.flys.utils.FLYSUtils; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FileUploadService extends FLYSService { + + /** The logger used in this service.*/ + private static Logger logger = Logger.getLogger(FileUploadService.class); + + /** XPath that points to the artifact uuid.*/ + public static final String XPATH_ARTIFACT_UUID = + "/upload/artifact-uuid/text()"; + + /** XPath that points to the base64 encoded data.*/ + public static final String XPATH_DATA = "/upload/data/text()"; + + public FileUploadService() { + } + + + @Override + protected Document doProcess( + Document data, + GlobalContext context, + CallMeta callMeta + ) { + logger.debug("FileUploadService.process"); + + String uuid = extractUuid(data); + + byte[] fileData = extractData(data); + if (fileData != null) { + try { + String shapePath = FLYSUtils.getXPathString( + FLYSUtils.XPATH_SHAPEFILE_DIR); + + File artifactDir = FileTools.getDirectory(shapePath, uuid); + FileOutputStream fos = + new FileOutputStream( + new File(artifactDir, "user-rgd.zip")); + try { + fos.write(fileData); + } + finally { + fos.close(); + } + } + catch (IOException ioe) { + logger.warn(ioe, ioe); + } + } + else { + logger.debug("No data in uploaded xml."); + } + + Document doc = XMLUtils.newDocument(); + ElementCreator ec = new ElementCreator(doc, null, null); + Element resp = ec.create("response"); + doc.appendChild(resp); + + return doc; + } + + + protected String extractUuid(Document data) { + return XMLUtils.xpathString( + data, XPATH_ARTIFACT_UUID, ArtifactNamespaceContext.INSTANCE); + } + + + protected byte[] extractData(Document data) { + String b64Data = XMLUtils.xpathString( + data, XPATH_DATA, ArtifactNamespaceContext.INSTANCE); + + if (b64Data != null && b64Data.length() > 0) { + byte[] fileData = Base64.decodeBase64(b64Data); + return fileData; + } + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,486 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.artifactdatabase.DefaultService; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.Service; + +import de.intevation.flys.artifacts.model.FixingsColumn; +import de.intevation.flys.artifacts.model.FixingsColumnFactory; +import de.intevation.flys.artifacts.model.FixingsFilterBuilder; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; + +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.FixingsOverviewFactory; +import de.intevation.flys.artifacts.model.GaugeFinder; +import de.intevation.flys.artifacts.model.GaugeFinderFactory; +import de.intevation.flys.artifacts.model.GaugeRange; + +import de.intevation.flys.artifacts.model.fixings.QWI; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.backend.SessionHolder; + +import de.intevation.flys.jfree.ShapeRenderer; + +import de.intevation.flys.utils.Formatter; +import de.intevation.flys.utils.Pair; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Transparency; + +import java.awt.geom.Rectangle2D; + +import java.awt.image.BufferedImage; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItemCollection; + +import org.jfree.chart.axis.NumberAxis; + +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.ValueMarker; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.data.Range; + +import org.jfree.ui.RectangleAnchor; +import org.jfree.ui.TextAnchor; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +/** Serve chart of Fixings at certain km. */ +public class FixingsKMChartService +extends DefaultService +{ + private static final Logger log = + Logger.getLogger(FixingsKMChartService.class); + + public static final int DEFAULT_WIDTH = 240; + public static final int DEFAULT_HEIGHT = 180; + + public static final String [] I18N_Q_SECTOR_BOARDERS = { + "fix.km.chart.q.sector.border0", + "fix.km.chart.q.sector.border1", + "fix.km.chart.q.sector.border2" + }; + + public static final String [] DEFAULT_Q_SECTOR_BORDERS = { + "(MNQ + MQ)/2", + "(MQ + MHQ)/2", + "HQ5" + }; + + public static final String I18N_CHART_LABEL_DATE = + "fix.km.chart.label.date"; + + public static final String DEFAULT_CHART_LABEL_DATE = + "yyyy/MM/dd"; + + public static final String I18N_CHART_TITLE = + "fix.km.chart.title"; + + public static final String DEFAULT_CHART_TITLE = + "Fixings {0} km {1,number,#.###}"; + + public static final String I18N_Q_AXIS = + "fix.km.chart.q.axis"; + + public static final String DEFAULT_Q_AXIS = + "Q [m\u00b3/s]"; + + public static final String I18N_W_AXIS = + "fix.km.chart.w.axis"; + + public static final String DEFAULT_W_AXIS = + "W [NN + m]"; + + public static final String I18N_MEASURED = + "fix.km.chart.measured"; + + public static final String DEFAULT_MEASURED = + "measured"; + + public static final String I18N_INTERPOLATED = + "fix.km.chart.interpolated"; + + public static final String DEFAULT_INTERPOLATED = + "interpolated"; + + public static final String DEFAULT_FORMAT = "png"; + + // TODO: Load fancy image from resources. + public static final byte [] EMPTY = { + (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, + (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d, + (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b, + (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47, + (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce, + (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48, + (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00, + (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74, + (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07, + (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10, + (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77, + (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45, + (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f, + (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e, + (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc, + (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44, + (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7, + (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00, + (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44, + (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82 + }; + + private static final Output empty() { + return new Output(EMPTY, "image/png"); + } + + @Override + public Service.Output process( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("FixingsKMChartService.process"); + + SessionHolder.acquire(); + try { + return doProcess(data, globalContext, callMeta); + } + finally { + SessionHolder.HOLDER.get().close(); + SessionHolder.release(); + } + } + + protected Service.Output doProcess( + Document input, + GlobalContext globalContext, + CallMeta callMeta + ) { + String river = getRiverName(input); + Double km = getKM(input); + Dimension extent = getExtent(input); + String format = getFormat(input); + + if (river == null || km == null) { + log.warn("River and/or km invalid."); + return empty(); + } + + FixingsOverview overview = FixingsOverviewFactory.getOverview(river); + + if (overview == null) { + log.warn("No overview found for river '" + river + "'"); + return empty(); + } + + FixingsFilterBuilder ffb = new FixingsFilterBuilder(input); + + List<Fixing.Column> columns = overview.filter( + ffb.getRange(), + ffb.getFilter()); + + List<Pair<Fixing.Column, FixingsColumn>> cols = + new ArrayList<Pair<Fixing.Column, FixingsColumn>>(); + + for (Fixing.Column col: columns) { + FixingsColumn data = + FixingsColumnFactory.INSTANCE.getColumnData(col); + if (data != null) { + cols.add(new Pair<Fixing.Column, FixingsColumn>(col, data)); + } + } + + JFreeChart chart = createChart(cols, river, km, callMeta); + + return encode(chart, extent, format); + } + + protected static Output encode( + JFreeChart chart, + Dimension extent, + String format + ) { + BufferedImage image = chart.createBufferedImage( + extent.width, extent.height, + Transparency.BITMASK, + null); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + try { + ImageIO.write(image, format, out); + } + catch (IOException ioe) { + log.warn("writing image failed", ioe); + return empty(); + } + + return new Output(out.toByteArray(), "image/" + format); + } + + protected static JFreeChart createChart( + List<Pair<Fixing.Column, FixingsColumn>> cols, + String river, + double km, + CallMeta callMeta + ) { + String labelFormat = Resources.getMsg( + callMeta, I18N_CHART_LABEL_DATE, DEFAULT_CHART_LABEL_DATE); + + QWSeriesCollection.LabelGenerator lg = + new QWSeriesCollection.DateFormatLabelGenerator(labelFormat); + + QWSeriesCollection dataset = new QWSeriesCollection(lg); + + double [] w = new double[1]; + for (Pair<Fixing.Column, FixingsColumn> col: cols) { + boolean interpolated = !col.getB().getW(km, w); + double q = col.getB().getQ(km); + if (!Double.isNaN(w[0]) && !Double.isNaN(q)) { + QWI qw = new QWI( + q, w[0], + col.getA().getDescription(), + col.getA().getStartTime(), + interpolated, 0); + dataset.add(qw); + } + } + + String title = Resources.format( + callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river, km); + + String qAxis = Resources.getMsg( + callMeta, I18N_Q_AXIS, DEFAULT_Q_AXIS); + + String wAxis = Resources.getMsg( + callMeta, I18N_W_AXIS, DEFAULT_W_AXIS); + + JFreeChart chart = ChartFactory.createXYLineChart( + title, + qAxis, + wAxis, + null, + PlotOrientation.VERTICAL, + true, + true, + false); + + XYPlot plot = (XYPlot)chart.getPlot(); + + NumberAxis qA = (NumberAxis)plot.getDomainAxis(); + qA.setNumberFormatOverride(Formatter.getWaterlevelQ(callMeta)); + + NumberAxis wA = (NumberAxis)plot.getRangeAxis(); + wA.setNumberFormatOverride(Formatter.getWaterlevelW(callMeta)); + + plot.setRenderer(0, dataset.createRenderer()); + plot.setDataset(0, dataset); + + Rectangle2D area = dataset.getArea(); + + if (area != null) { + double height = area.getHeight(); + double wInset = Math.max(height, 0.01) * 0.25d; + + wA.setAutoRangeIncludesZero(false); + wA.setRange(new Range( + area.getMinY() - wInset, + area.getMaxY() + wInset)); + } + + final String measuredS = Resources.getMsg( + callMeta, I18N_MEASURED, DEFAULT_MEASURED); + + final String interpolatedS = Resources.getMsg( + callMeta, I18N_INTERPOLATED, DEFAULT_INTERPOLATED); + + LegendItemCollection lic = plot.getLegendItems(); + dataset.addLegendItems(lic, new ShapeRenderer.LabelGenerator() { + @Override + public String createLabel(ShapeRenderer.Entry entry) { + return entry.getFilled() ? measuredS : interpolatedS; + } + }); + plot.setFixedLegendItems(lic); + + applyQSectorMarkers(plot, river, km, callMeta); + + chart.setBackgroundPaint(Color.white); + plot.setBackgroundPaint(Color.white); + plot.setDomainGridlinePaint(Color.gray); + plot.setRangeGridlinePaint(Color.gray); + plot.setDomainGridlinesVisible(true); + plot.setRangeGridlinesVisible(true); + + return chart; + } + + /** Add domain markers to plot that indicate Q-sectors. */ + protected static void applyQSectorMarkers( + XYPlot plot, + String river, + double km, + CallMeta meta + ) { + GaugeFinderFactory ggf = GaugeFinderFactory.getInstance(); + GaugeFinder gf = ggf.getGaugeFinder(river); + + if (gf == null) { + log.warn("No gauge finder found for river '" + river + "'"); + return; + } + + GaugeRange gr = gf.find(km); + if (gr == null) { + log.debug("No gauge range found for km " + + km + " on river " + river + "."); + return; + } + + if (log.isDebugEnabled()) { + log.debug(gr); + } + + for (int i = 0; i < I18N_Q_SECTOR_BOARDERS.length; ++i) { + String key = I18N_Q_SECTOR_BOARDERS[i]; + String def = DEFAULT_Q_SECTOR_BORDERS[i]; + String label = Resources.getMsg(meta, key, def); + + Marker m = createQSectorMarker( + gr.getSectorBorder(i), + label); + + if (m != null) { + plot.addDomainMarker(m); + } + } + } + + protected static Marker createQSectorMarker(double value, String label) { + if (Double.isNaN(value)) { + return null; + } + Marker m = new ValueMarker(value); + m.setPaint(Color.black); + m.setStroke(new BasicStroke()); + m.setLabel(label); + m.setLabelAnchor(RectangleAnchor.TOP_LEFT); + m.setLabelTextAnchor(TextAnchor.TOP_LEFT); + return m; + } + + protected static String getRiverName(Document input) { + NodeList rivers = input.getElementsByTagName("river"); + + if (rivers.getLength() == 0) { + return null; + } + + String river = ((Element)rivers.item(0)).getAttribute("name"); + + return river.length() > 0 ? river : null; + } + + protected static Double getKM(Document input) { + NodeList kms = input.getElementsByTagName("km"); + + if (kms.getLength() == 0) { + return null; + } + + String km = ((Element)kms.item(0)).getAttribute("value"); + + try { + return Double.valueOf(km); + } + catch (NumberFormatException nfe) { + log.warn("Km '" + km + " is not a valid number."); + return null; + } + } + + protected static Dimension getExtent(Document input) { + + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + + NodeList extents = input.getElementsByTagName("extent"); + + if (extents.getLength() > 0) { + Element element = (Element)extents.item(0); + String w = element.getAttribute("width"); + String h = element.getAttribute("height"); + + try { + width = Math.max(1, Integer.parseInt(w)); + } + catch (NumberFormatException nfe) { + log.warn("width '" + w + "' is not a valid."); + } + + try { + height = Math.max(1, Integer.parseInt(h)); + } + catch (NumberFormatException nfe) { + log.warn("height '" + h + "' is not a valid"); + } + } + + return new Dimension(width, height); + } + + protected static String getFormat(Document input) { + String format = DEFAULT_FORMAT; + + NodeList formats = input.getElementsByTagName("format"); + + if (formats.getLength() > 0) { + String type = ((Element)formats.item(0)).getAttribute("type"); + if (type.length() > 0) { + format = type; + } + } + + return format; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,63 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.model.FixingsFilterBuilder; + +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; + +import de.intevation.flys.artifacts.model.Range; + +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.FixingsOverviewFactory; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class FixingsOverviewService +extends FLYSService +{ + private static Logger log = + Logger.getLogger(FixingsOverviewService.class); + + public FixingsOverviewService() { + } + + @Override + public Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("FixingsOverviewService.doProcess"); + + Document document = XMLUtils.newDocument(); + + NodeList nodes = data.getElementsByTagName("river"); + + String river = nodes.getLength() > 0 + ? ((Element)nodes.item(0)).getAttribute("name") + : ""; + + FixingsOverview overview = FixingsOverviewFactory.getOverview(river); + + if (overview != null) { + FixingsFilterBuilder ffb = new FixingsFilterBuilder(data); + Range range = ffb.getRange(); + Filter filter = ffb.getFilter(); + overview.generateOverview(document, range, filter); + } + else { + log.warn("No overview for river '" + river + "' available."); + } + + return document; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.artifacts.services; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.Range; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.RiverFactory; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class GaugeInfoService extends FLYSService { + + interface Filter { + boolean apply(Gauge gauge); + } + + + protected class ReferenceNumberFilter implements Filter { + private long refNr; + + public ReferenceNumberFilter(long refNr) { + this.refNr = refNr; + } + + @Override + public boolean apply(Gauge gauge) { + logger.debug("Test gauge '" + gauge.getName() + "'"); + + if (gauge != null && gauge.getOfficialNumber() == refNr) { + return true; + } + else { + return false; + } + } + } // end of ReferenceNumberFilter class + + + /** The logger that is used by this service.*/ + private static Logger logger = Logger.getLogger(GaugeInfoService.class); + + + public static final String XPATH_RIVERNAME = "/art:river/@name"; + + public static final String XPATH_REFERENCE_NR + = "/art:river/art:filter/art:gauge/text()"; + + + public GaugeInfoService() { + } + + + @Override + public Document doProcess( + Document data, + GlobalContext context, + CallMeta callMeta + ) { + logger.debug("GaugeInfoService.process"); + + if (logger.isDebugEnabled()) { + logger.debug(XMLUtils.toString(data)); + } + + River river = getRiverFromRequest(data); + + List<Filter> filters = getFilters(data); + List<Gauge> allGauges = river.getGauges(); + List<Gauge> filtered = new ArrayList<Gauge>(); + + for (Gauge g: allGauges) { + for (Filter f: filters) { + if (f.apply(g)) { + filtered.add(g); + break; + } + } + } + + return buildInfoDocument(filtered); + } + + + protected River getRiverFromRequest(Document data) { + String rivername = XMLUtils.xpathString( + data, + XPATH_RIVERNAME, + ArtifactNamespaceContext.INSTANCE); + + logger.debug("Return Gauge info for River '" + rivername + "'"); + + return rivername != null ? RiverFactory.getRiver(rivername) : null; + } + + + protected List<Filter> getFilters(Document data) { + List<Filter> filters = new ArrayList<Filter>(); + + String refNr = XMLUtils.xpathString( + data, + XPATH_REFERENCE_NR, + ArtifactNamespaceContext.INSTANCE); + + if (refNr != null && refNr.length() > 0) { + try { + filters.add(new ReferenceNumberFilter(Long.valueOf(refNr))); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + return filters; + } + + + protected Document buildInfoDocument(List<Gauge> gauges) { + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element service = cr.create("service"); + + logger.debug("Append " + gauges.size() + " gauges to info doc."); + + for (Gauge g: gauges) { + Range r = g.getRange(); + + Element el = cr.create("gauge"); + cr.addAttr(el, "name", g.getName()); + cr.addAttr(el, "lower", String.valueOf(r.getA().doubleValue())); + cr.addAttr(el, "upper", String.valueOf(r.getB().doubleValue())); + + service.appendChild(el); + } + + doc.appendChild(service); + + return doc; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,153 @@ +package de.intevation.flys.artifacts.services; + +import java.math.BigDecimal; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.MinMaxWQ; +import de.intevation.flys.model.Range; +import de.intevation.flys.model.River; + +/** + * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a> + */ +public class GaugeOverviewInfoService extends FLYSService { + + private static final Logger logger = Logger.getLogger( + GaugeOverviewInfoService.class); + + public static final String RIVER_XPATH = "/art:river/text()"; + + @Override + public Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("GaugeOverviewInfoService.process"); + + String riverstr = XMLUtils.xpathString( + data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE); + + River river = RiverFactory.getRiver(riverstr); + + Document result = XMLUtils.newDocument(); + + if (river == null) { + logger.warn("No river with name " + riverstr + " found."); + return result; + } + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element go = ec.create("gauge-info"); + + double[] minmax = river.determineMinMaxDistance(); + double[] minmaxq = river.determineMinMaxQ(); + + Element r = ec.create("river"); + ec.addAttr(r, "name", river.getName(), true); + ec.addAttr(r, "start", Double.toString(minmax[0]), true); + ec.addAttr(r, "end", Double.toString(minmax[1]), true); + ec.addAttr(r, "wstunit", river.getWstUnit().getName(), true); + ec.addAttr(r, "kmup", Boolean.toString(river.getKmUp()), true); + ec.addAttr(r, "minq", Double.toString(minmaxq[0]), true); + ec.addAttr(r, "maxq", Double.toString(minmaxq[1]), true); + + Element egs = ec.create("gauges"); + + List<Gauge> gauges = river.getGauges(); + + if (logger.isDebugEnabled()) { + logger.debug("Loaded gauges: " + gauges); + } + + for (Gauge gauge: river.getGauges()) { + Element eg = ec.create("gauge"); + + String name = gauge.getName(); + if (name != null) { + ec.addAttr(eg, "name", gauge.getName(), true); + } + + String aeo = getGaugeValue(gauge.getAeo()); + if (aeo != null) { + ec.addAttr(eg, "aeo", aeo, true); + } + + String datum = getGaugeValue(gauge.getDatum()); + if (datum != null) { + ec.addAttr(eg, "datum", datum, true); + } + + Range range = gauge.getRange(); + if (range != null) { + BigDecimal a = range.getA(); + if (a != null) { + double min = a.doubleValue(); + ec.addAttr(eg, "start", Double.toString(min), true); + } + + BigDecimal b = range.getB(); + if (b != null) { + double max = range.getB().doubleValue(); + ec.addAttr(eg, "end", Double.toString(max), true); + } + } + MinMaxWQ minmaxwq = gauge.fetchMaxMinWQ(); + String minw = getGaugeValue(minmaxwq.getMinW()); + String maxw = getGaugeValue(minmaxwq.getMaxW()); + String minq = getGaugeValue(minmaxwq.getMinQ()); + String maxq = getGaugeValue(minmaxwq.getMaxQ()); + + if (minw != null) { + ec.addAttr(eg, "minw", minw, true); + } + if (maxw != null) { + ec.addAttr(eg, "maxw", maxw, true); + } + if (minq != null) { + ec.addAttr(eg, "minq", minq, true); + } + if (maxq != null) { + ec.addAttr(eg, "maxq", maxq, true); + } + + String station = getGaugeValue(gauge.getStation()); + if (station != null) { + ec.addAttr(eg, "station", station, true); + } + + egs.appendChild(eg); + } + + go.appendChild(r); + go.appendChild(egs); + result.appendChild(go); + + return result; + } + + /** + * Returns a Double from a BigDecimal value or null if value is null + */ + private static String getGaugeValue(BigDecimal value) { + return value != null + ? Double.toString(value.doubleValue()) + : ""; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,304 @@ +package de.intevation.flys.artifacts.services; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.MainValue; +import de.intevation.flys.model.MainValueType; +import de.intevation.flys.model.NamedMainValue; +import de.intevation.flys.model.Range; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.RiverFactory; + + +/** + * This service returns the main values of a river's gauge based on the start + * and end point of the river. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MainValuesService extends FLYSService { + + /** The logger that is used by this service.*/ + private static Logger logger = Logger.getLogger(MainValuesService.class); + + + /** The XPath that points to the river definition of the incoming request.*/ + public static final String XPATH_RIVER = "/art:mainvalues/art:river/text()"; + + /** The XPath that points to the start definition of the incoming request.*/ + public static final String XPATH_START = "/art:mainvalues/art:start/text()"; + + /** The XPath that points to the end definition of the incoming request.*/ + public static final String XPATH_END = "/art:mainvalues/art:end/text()"; + + /** + * The default constructor. + */ + public MainValuesService() { + } + + private static final Document error(String msg) { + logger.debug(msg); + return XMLUtils.newDocument(); + } + + + @Override + public Document doProcess( + Document data, + GlobalContext context, + CallMeta callMeta + ) { + logger.debug("MainValuesService.process"); + + River river = getRequestedRiver(data); + if (river == null) { + return error("no river found."); + } + + double[] minmax = getRequestedStartEnd(data, river); + Gauge gauge = river.determineGauge(minmax[0], minmax[1]); + + if (gauge == null) { + return error("no gauge found."); + } + + List<MainValue> mainValues = getMainValues(river, gauge); + + return buildDocument(river, gauge, mainValues, context); + } + + + /** + * This method extracts the river from the incoming request. If no river + * string was found or no river is found in the database based on this + * string a NullPointerException is thrown. + * + * @param data The incoming request data. + * + * @return the River object. + */ + protected River getRequestedRiver(Document data) + throws NullPointerException + { + logger.debug("MainValuesService.getRiver"); + + String riverStr = XMLUtils.xpathString( + data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); + + return riverStr != null && (riverStr = riverStr.trim()).length() > 0 + ? RiverFactory.getRiver(riverStr) + : null; + } + + + /** + * This method extracts the start and end point from incoming request + * document and returns both values in an array. If no start and end strings + * are found in the document, the min/max values of the <i>river</i> are + * returned. + * + * @param data The incoming request data. + * @param river The river of the request. + * + * @return the start and end point. + */ + protected double[] getRequestedStartEnd(Document data, River river) { + logger.debug("MainValuesService.getStartEnd"); + + String startStr = XMLUtils.xpathString( + data, XPATH_START, ArtifactNamespaceContext.INSTANCE); + + String endStr = XMLUtils.xpathString( + data, XPATH_END, ArtifactNamespaceContext.INSTANCE); + + if (startStr == null || endStr == null) { + return river.determineMinMaxDistance(); + } + + try { + double start = Double.parseDouble(startStr); + double end = Double.parseDouble(endStr); + + if (logger.isDebugEnabled()) { + logger.debug("Found start: " + start); + logger.debug("Found end: " + end); + } + + return new double[] { start, end }; + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + return river.determineMinMaxDistance(); + } + } + + + /** + * This method creates the result document that includes the main values of + * the specified <i>gauge</i>. + * + * @param river The river. + * @param gauge The gauge. + * + * @return a document that includes the main values of the specified river + * at the specified gauge. + */ + protected List<MainValue> getMainValues(River river, Gauge gauge) { + + if (logger.isDebugEnabled()) { + logger.debug("MainValuesService.buildMainValues"); + logger.debug("River: " + river.getName()); + logger.debug("Gauge: " + gauge.getName()); + } + + List<MainValue> mainValues = gauge.getMainValues(); + + if (logger.isDebugEnabled()) { + logger.debug(mainValues.size() + " main values found."); + } + + return mainValues; + } + + + protected Document buildDocument( + River river, + Gauge gauge, + List<MainValue> mainValues, + Object context) + { + logger.debug("MainValuesService.buildDocument"); + + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element rootEl = cr.create("service"); + cr.addAttr(rootEl, "name", "mainvalues"); + + doc.appendChild(rootEl); + + appendMetaInformation(doc, rootEl, river, gauge, context); + appendMainValues(doc, rootEl, mainValues, context); + + return doc; + } + + + /** + * This method appends some meta information to the result document. + * Currently, the river's and gauge's names and the gauge's range are + * appended. + * + * @param root The root element of the result document. + * @param river The river. + * @param gauge The gauge. + * @param context The context object. + */ + protected void appendMetaInformation( + Document doc, + Element root, + River river, + Gauge gauge, + Object context) + { + logger.debug("MainValuesService.appendMetaInformation"); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Range range = gauge.getRange(); + + Element riverEl = cr.create("river"); + cr.addAttr(riverEl, "name", river.getName()); + + Element gaugeEl = cr.create("gauge"); + cr.addAttr(gaugeEl, "name", gauge.getName()); + cr.addAttr(gaugeEl, "from", range.getA().toString()); + cr.addAttr(gaugeEl, "to", range.getB().toString()); + + root.appendChild(riverEl); + root.appendChild(gaugeEl); + } + + + protected void appendMainValues( + Document doc, + Element root, + List<MainValue> mainValues, + Object context) + { + logger.debug("MainValuesService.appendMainValues"); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element list = cr.create("mainvalues"); + + for (MainValue mainValue: mainValues) { + Element newEl = buildMainValueElement(doc, mainValue, context); + + if (newEl != null) { + list.appendChild(newEl); + } + } + + root.appendChild(list); + } + + + /** + * This method builds a concrete mainvalue element. This element consists of + * three attributes: the value, its name and its type. + * + * @param doc The owner document. + * @param mainValue The mainvalue. + * @param context The context object. + * + * @return a mainvalue element. + */ + protected Element buildMainValueElement( + Document doc, + MainValue mainValue, + Object context) + { + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + NamedMainValue namedMainValue = mainValue.getMainValue(); + MainValueType mainValueType = namedMainValue.getType(); + + Element el = cr.create("mainvalue"); + + cr.addAttr(el, "value", mainValue.getValue().toString()); + cr.addAttr(el, "name", namedMainValue.getName()); + cr.addAttr(el, "type", mainValueType.getName()); + + return el; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,148 @@ +package de.intevation.flys.artifacts.services; + +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.HashMap; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.Element; + +import javax.xml.xpath.XPathConstants; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.Config; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.XMLService; + +import de.intevation.flys.model.River; + +import de.intevation.flys.utils.GeometryUtils; + +/** + * This service provides information about the supported rivers by this + * application. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MapInfoService extends XMLService { + + /** XPath that points to the river.*/ + public static final String XPATH_RIVER = "/mapinfo/river/text()"; + + public static final String XPATH_RIVER_PROJECTION = + "/artifact-database/floodmap/river[@name=$river]/srid/@value"; + + public static final String XPATH_RIVER_BACKGROUND = + "/artifact-database/floodmap/river[@name=$river]/background-wms"; + + public static final String XPATH_RIVER_WMS = + "/artifact-database/floodmap/river[@name=$river]/river-wms/@url"; + + + /** The logger used in this service.*/ + private static Logger logger = Logger.getLogger(MapInfoService.class); + + + /** + * The default constructor. + */ + public MapInfoService() { + } + + protected static String getStringXPath( + String query, + Map<String, String> variables + ) { + return (String)XMLUtils.xpath( + Config.getConfig(), query, XPathConstants.STRING, + null, variables); + } + + protected static Node getNodeXPath( + String query, + Map<String, String> variables + ) { + return (Node)XMLUtils.xpath( + Config.getConfig(), query, XPathConstants.NODE, + null, variables); + } + + @Override + public Document processXML( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("MapInfoService.process"); + + Document result = XMLUtils.newDocument(); + ElementCreator cr = new ElementCreator(result, null, null); + + Element mapinfo = cr.create("mapinfo"); + result.appendChild(mapinfo); + + String river = extractRiver(data); + if (river == null || river.length() == 0) { + logger.warn("Cannot generate information: river is empty!"); + return result; + } + + Element root = cr.create("river"); + cr.addAttr(root, "name", river); + mapinfo.appendChild(root); + + Envelope env = GeometryUtils.getRiverBoundary(river); + if (env != null) { + String bounds = GeometryUtils.jtsBoundsToOLBounds(env); + logger.debug("River '" + river + "' bounds: " + bounds); + + Element bbox = cr.create("bbox"); + cr.addAttr(bbox, "value", bounds); + root.appendChild(bbox); + } + + Map<String, String> vars = new HashMap<String, String>(); + vars.put("river", river); + + String sridStr = getStringXPath(XPATH_RIVER_PROJECTION, vars); + + if (sridStr != null && sridStr.length() > 0) { + Element srid = cr.create("srid"); + cr.addAttr(srid, "value", sridStr); + root.appendChild(srid); + } + + Element back = (Element)getNodeXPath(XPATH_RIVER_BACKGROUND, vars); + if (back != null) { + Element background = cr.create("background-wms"); + cr.addAttr(background, "url", back.getAttribute("url")); + cr.addAttr(background, "layers", back.getAttribute("layers")); + root.appendChild(background); + } + + String wmsStr = getStringXPath(XPATH_RIVER_WMS, vars); + if (wmsStr != null && wmsStr.length() > 0) { + Element wms = cr.create("river-wms"); + cr.addAttr(wms, "url", wmsStr); + root.appendChild(wms); + } + + return result; + } + + + protected String extractRiver(Document data) { + return XMLUtils.xpathString( + data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,169 @@ +package de.intevation.flys.artifacts.services; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.HashMap; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.StringUtils; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; + +import de.intevation.flys.artifacts.datacage.Recommendations; + +import de.intevation.flys.artifacts.FLYSArtifact; + +public class MetaDataService +extends FLYSService +{ + private static Logger log = Logger.getLogger(MetaDataService.class); + + public static final String XPATH_ARTIFACT_ID = "/art:meta/art:artifact-id/@value"; + public static final String XPATH_USER_ID = "/art:meta/art:user-id/@value"; + public static final String XPATH_OUTS = "/art:meta/art:outs/@value"; + public static final String XPATH_PARAMETERS = "/art:meta/art:parameters/@value"; + + /** The global context key of the artifact database. */ + public static final String ARTIFACT_DATA_BASE_KEY = + "global.artifact.database"; + + public MetaDataService() { + } + + @Override + protected Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("MetaDataService.process"); + + String artifactId = XMLUtils.xpathString( + data, XPATH_ARTIFACT_ID, ArtifactNamespaceContext.INSTANCE); + + if (artifactId != null + && (artifactId = artifactId.trim()).length() == 0) { + artifactId = null; + } + + String userId = XMLUtils.xpathString( + data, XPATH_USER_ID, ArtifactNamespaceContext.INSTANCE); + + if (userId != null + && (userId = userId.trim()).length() == 0) { + userId = null; + } + + String outs = XMLUtils.xpathString( + data, XPATH_OUTS, ArtifactNamespaceContext.INSTANCE); + + String parameters = XMLUtils.xpathString( + data, XPATH_PARAMETERS, ArtifactNamespaceContext.INSTANCE); + + return doService( + artifactId, userId, outs, parameters, globalContext); + } + + protected static Map<String, Object> splitParameters( + String parameters, + Map<String, Object> data + ) { + if (parameters != null) { + String [] parts = parameters.split("\\s*;\\s*"); + for (String part: parts) { + String [] kv = part.split("\\s*:\\s*"); + if (kv.length < 2 || (kv[0] = kv[0].trim()).length() == 0) { + continue; + } + String [] values = kv[1].split("\\s*,\\s*"); + data.put(kv[0], values.length == 1 ? values[0] : values); + } + } + return data; + } + + protected Document doService( + String artifactId, + String userId, + String outsString, + String parameters, + GlobalContext globalContext + ) { + Document result = XMLUtils.newDocument(); + + FLYSArtifact flysArtifact; + + if (log.isDebugEnabled()) { + log.debug("artifact : " + artifactId); + log.debug("user : " + userId); + log.debug("outs : " + outsString); + log.debug("parameters: " + parameters); + } + + if (userId != null && !StringUtils.checkUUID(userId)) { + log.warn("'" + userId + "' is not a UUID"); + return result; + } + + if (artifactId != null) { + if (!StringUtils.checkUUID(artifactId)) { + log.warn("'" + artifactId + "' is not a UUID"); + return result; + } + + Object dbObject = + (ArtifactDatabase)globalContext.get(ARTIFACT_DATA_BASE_KEY); + + if (!(dbObject instanceof ArtifactDatabase)) { + log.error("Cannot find artifact database"); + return result; + } + + ArtifactDatabase db = (ArtifactDatabase)dbObject; + + Artifact artifact; + + try { + artifact = db.getRawArtifact(artifactId); + } + catch (ArtifactDatabaseException adbe) { + log.warn("fetching artifact failed", adbe); + return result; + } + + if (!(artifact instanceof FLYSArtifact)) { + log.warn("artifact is not a FLYS artifact."); + return result; + } + + flysArtifact = (FLYSArtifact)artifact; + } + else { + flysArtifact = null; + } + + + Map<String, Object> data = splitParameters( + parameters, new HashMap<String, Object>()); + + String [] outs = outsString == null + ? new String [0] + : outsString.split("\\s*,\\s*"); + + Recommendations rec = Recommendations.getInstance(); + rec.recommend( + flysArtifact, userId, outs, data, result); + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/ModuleService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,62 @@ +package de.intevation.flys.artifacts.services; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.flys.artifacts.model.Module; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.resources.Resources; + +public class ModuleService extends FLYSService { + + private static final String MODULE = "module"; + + private static Logger logger = Logger.getLogger(ModuleService.class); + + protected Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("ModuleService.process"); + + Document result = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element em = ec.create("modules"); + List<Module> modules = (List<Module>)globalContext.get(FLYSContext.MODULES); + + for (Module module : modules) { + Element m = ec.create("module"); + ec.addAttr(m, "name", module.getName(), true); + String localname = Resources.getMsg(callMeta, + MODULE + "." + module.getName(), module.getName()); + ec.addAttr(m, "localname", localname, true); + + if (module.isSelected()) { + ec.addAttr(m, "selected", "true", true); + } + + em.appendChild(m); + } + + result.appendChild(em); + + return result; + } +} + +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,227 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.flys.artifacts.model.fixings.QWI; + +import de.intevation.flys.java2d.ShapeUtils; + +import de.intevation.flys.jfree.ShapeRenderer; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Paint; +import java.awt.Shape; + +import java.awt.geom.Rectangle2D; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; + +import org.jfree.chart.labels.XYItemLabelGenerator; + +import org.jfree.chart.renderer.xy.StandardXYItemRenderer; + +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +public class QWSeriesCollection +extends XYSeriesCollection +implements XYItemLabelGenerator +{ + public interface LabelGenerator { + String createLabel(QWI qw); + } // interface LabelGenerator + + public static class DateFormatLabelGenerator + implements LabelGenerator + { + protected DateFormat format; + + public DateFormatLabelGenerator() { + this("dd.MM.yyyy"); + } + + public DateFormatLabelGenerator(String format) { + this(new SimpleDateFormat(format)); + } + + public DateFormatLabelGenerator(DateFormat format) { + this.format = format; + } + + @Override + public String createLabel(QWI qw) { + Date date = qw.getDate(); + return date != null ? format.format(date) : ""; + } + } // class DateFormatLabelGenerator + + public static final LabelGenerator SIMPLE_GENERATOR = + new DateFormatLabelGenerator(); + + protected Date minDate; + protected Date maxDate; + + protected List<List<QWI>> labels; + + protected Rectangle2D area; + + protected LabelGenerator labelGenerator; + + protected Map<ShapeRenderer.Entry, Integer> knownShapes = + new HashMap<ShapeRenderer.Entry, Integer>(); + + public QWSeriesCollection() { + labels = new ArrayList<List<QWI>>(); + labelGenerator = SIMPLE_GENERATOR; + } + + public QWSeriesCollection(LabelGenerator labelGenerator) { + this(); + this.labelGenerator = labelGenerator; + } + + protected static ShapeRenderer.Entry classify(QWI qw) { + boolean interpolated = qw.getInterpolated(); + + Shape shape = interpolated + ? ShapeUtils.INTERPOLATED_SHAPE + : ShapeUtils.MEASURED_SHAPE; + + boolean filled = !interpolated; + Color color = Color.blue; + + return new ShapeRenderer.Entry(shape, color, filled); + } + + public void add(QWI qw) { + + ShapeRenderer.Entry key = classify(qw); + + Integer seriesNo = knownShapes.get(key); + + XYSeries series; + + if (seriesNo == null) { + seriesNo = Integer.valueOf(getSeriesCount()); + knownShapes.put(key, seriesNo); + series = new XYSeries(seriesNo, false); + addSeries(series); + labels.add(new ArrayList<QWI>()); + } + else { + series = getSeries(seriesNo); + } + + series.add(qw.getQ(), qw.getW()); + + labels.get(seriesNo).add(qw); + + extendDateRange(qw); + extendArea(qw); + } + + protected void extendDateRange(QWI qw) { + Date date = qw.getDate(); + if (date != null) { + if (minDate == null) { + minDate = maxDate = date; + } + else { + if (date.compareTo(minDate) < 0) { + minDate = date; + } + if (date.compareTo(maxDate) > 0) { + maxDate = date; + } + } + } + } + + protected void extendArea(QWI qw) { + if (area == null) { + area = new Rectangle2D.Double( + qw.getQ(), qw.getW(), 0d, 0d); + } + else { + area.add(qw.getQ(), qw.getW()); + } + } + + public Rectangle2D getArea() { + return area; + } + + public Date getMinDate() { + return minDate; + } + + public Date getMaxDate() { + return maxDate; + } + + public LabelGenerator getLabelGenerator() { + return labelGenerator; + } + + @Override + public String generateLabel(XYDataset dataset, int series, int item) { + return labelGenerator.createLabel(labels.get(series).get(item)); + } + + public StandardXYItemRenderer createRenderer() { + StandardXYItemRenderer renderer = new ShapeRenderer(knownShapes); + renderer.setBaseItemLabelGenerator(this); + renderer.setBaseSeriesVisibleInLegend(false); + renderer.setBaseItemLabelsVisible(true); + return renderer; + } + + public static final LegendItem legendItem( + String label, + Paint paint, + Shape shape, + boolean filled + ) { + BasicStroke stroke = new BasicStroke(); + return new LegendItem( + label, // label + null, // description + null, // tooltip + null, // url + true, // shape visible + shape, // shape + filled, // shape filled + filled ? paint : Color.white, // fill paint + true, // shape outline + paint, // outline paint + stroke, // outline stroke + false, // line visible + shape, // line + stroke, // line stroke + Color.white); + } + + public void addLegendItems( + LegendItemCollection lic, + ShapeRenderer.LabelGenerator lg + ) { + for (ShapeRenderer.Entry entry: knownShapes.keySet()) { + lic.add(legendItem( + lg.createLabel(entry), + entry.getPaint(), + entry.getShape(), + entry.getFilled())); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/RiverService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,63 @@ +package de.intevation.flys.artifacts.services; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.model.RiverFactory; + + +/** + * This service provides information about the supported rivers by this + * application. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class RiverService extends FLYSService { + + /** The logger used in this service.*/ + private static Logger logger = Logger.getLogger(RiverService.class); + + + protected Document doProcess( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + logger.debug("RiverService.process"); + + Document result = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + List<River> allRivers = RiverFactory.getRivers(); + + Element rivers = ec.create("rivers"); + + for (River river: allRivers) { + Element r = ec.create("river"); + ec.addAttr(r, "name", river.getName(), true); + + rivers.appendChild(r); + } + + result.appendChild(rivers); + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,316 @@ +package de.intevation.flys.artifacts.services; + +import de.intevation.artifactdatabase.DefaultService; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.Service; + +import de.intevation.flys.artifacts.model.SQOverview; +import de.intevation.flys.artifacts.model.SQOverviewFactory; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.backend.SedDBSessionHolder; + +import de.intevation.flys.utils.KMIndex; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Transparency; + +import java.awt.image.BufferedImage; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.util.Date; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; + +import org.jfree.chart.axis.DateAxis; + +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; + +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class SQKMChartService +extends DefaultService { + + private static final Logger log = + Logger.getLogger(SQKMChartService.class); + + public static final int DEFAULT_WIDTH = 240; + public static final int DEFAULT_HEIGHT = 180; + + public static final String I18N_CHART_LABEL = + "sq.km.chart.label"; + + public static final String DEFAULT_CHART_LABEL = + "Measuring Points"; + + public static final String I18N_CHART_TITLE = + "sq.km.chart.title"; + + public static final String DEFAULT_CHART_TITLE = + "Measuring points"; + + public static final String I18N_KM_AXIS = + "sq.km.chart.km.axis"; + + public static final String DEFAULT_KM_AXIS = + "km"; + + public static final String I18N_DATE_AXIS = + "sq.km.chart.date.axis"; + + public static final String DEFAULT_DATE_AXIS = + "Date"; + + public static final String DEFAULT_FORMAT = "png"; + + // TODO: Load fancy image from resources. + public static final byte [] EMPTY = { + (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, + (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d, + (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b, + (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47, + (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce, + (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48, + (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00, + (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00, + (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74, + (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07, + (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10, + (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77, + (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45, + (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f, + (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e, + (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc, + (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44, + (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7, + (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00, + (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00, + (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44, + (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82 + }; + + private static final Output empty() { + return new Output(EMPTY, "image/png"); + } + + @Override + public Service.Output process( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + log.debug("SQKMChartService.process"); + + SedDBSessionHolder.acquire(); + try { + return doProcess(data, globalContext, callMeta); + } + finally { + SedDBSessionHolder.HOLDER.get().close(); + SedDBSessionHolder.release(); + } + } + + protected Service.Output doProcess( + Document input, + GlobalContext globalContext, + CallMeta callMeta + ) { + String river = getRiverName(input); + Dimension extent = getExtent(input); + String format = getFormat(input); + + if (river == null) { + log.warn("River invalid."); + return empty(); + } + + SQOverview overview = SQOverviewFactory.getOverview(river); + + if (overview == null) { + log.warn("No overview found for river '" + river + "'"); + return empty(); + } + + KMIndex<List<Date>> entries = overview.filter(SQOverview.ACCEPT); + + JFreeChart chart = createChart(entries, river, callMeta); + + return encode(chart, extent, format); + } + + protected static Output encode( + JFreeChart chart, + Dimension extent, + String format + ) { + BufferedImage image = chart.createBufferedImage( + extent.width, extent.height, + Transparency.BITMASK, + null); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + try { + ImageIO.write(image, format, out); + } + catch (IOException ioe) { + log.warn("writing image failed", ioe); + return empty(); + } + + return new Output(out.toByteArray(), "image/" + format); + } + + protected static JFreeChart createChart( + KMIndex<List<Date>> entries, + String river, + CallMeta callMeta + ) { + + XYSeriesCollection dataset = new XYSeriesCollection(); + String key = Resources.format( + callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river); + + XYSeries series = new XYSeries(key); + for (KMIndex.Entry<List<Date>> e: entries) { + double km = e.getKm(); + List<Date> ds = e.getValue(); + for (Date d: ds) { + series.add(km, d.getTime()); + } + } + + dataset.addSeries(series); + String title = Resources.format( + callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river); + + String kmAxis = Resources.getMsg( + callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS); + + String dateAxis = Resources.getMsg( + callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS); + + JFreeChart chart = ChartFactory.createXYLineChart( + title, + kmAxis, + dateAxis, + null, + PlotOrientation.VERTICAL, + true, + true, + false); + + XYPlot plot = (XYPlot)chart.getPlot(); + + DateAxis dA = new DateAxis(); + plot.setRangeAxis(dA); + plot.setDataset(0, dataset); + + chart.setBackgroundPaint(Color.white); + plot.setBackgroundPaint(Color.white); + plot.setDomainGridlinePaint(Color.gray); + plot.setRangeGridlinePaint(Color.gray); + plot.setDomainGridlinesVisible(true); + plot.setRangeGridlinesVisible(true); + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer(); + + renderer.setSeriesPaint(0, Color.gray); + renderer.setSeriesLinesVisible(0, false); + renderer.setSeriesShapesVisible(0, true); + renderer.setDrawOutlines(true); + return chart; + } + + + protected static String getRiverName(Document input) { + NodeList rivers = input.getElementsByTagName("river"); + + if (rivers.getLength() == 0) { + return null; + } + + String river = ((Element)rivers.item(0)).getAttribute("name"); + + return river.length() > 0 ? river : null; + } + + protected static Dimension getExtent(Document input) { + + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + + NodeList extents = input.getElementsByTagName("extent"); + + if (extents.getLength() > 0) { + Element element = (Element)extents.item(0); + String w = element.getAttribute("width"); + String h = element.getAttribute("height"); + + try { + width = Math.max(1, Integer.parseInt(w)); + } + catch (NumberFormatException nfe) { + log.warn("width '" + w + "' is not a valid."); + } + + try { + height = Math.max(1, Integer.parseInt(h)); + } + catch (NumberFormatException nfe) { + log.warn("height '" + h + "' is not a valid"); + } + } + + return new Dimension(width, height); + } + + protected static String getFormat(Document input) { + String format = DEFAULT_FORMAT; + + NodeList formats = input.getElementsByTagName("format"); + + if (formats.getLength() > 0) { + String type = ((Element)formats.item(0)).getAttribute("type"); + if (type.length() > 0) { + format = type; + } + } + + return format; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/ThemeListingService.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,74 @@ +package de.intevation.flys.artifacts.services; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.themes.Theme; +import de.intevation.flys.themes.ThemeGroup; + +import de.intevation.flys.themes.ThemeFactory; +import de.intevation.flys.artifacts.context.FLYSContext; + +/** + * This service provides a list of themes filtered by the theme name. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class ThemeListingService extends FLYSService { + + /** The logger used in this service.*/ + private static Logger logger = Logger.getLogger(ThemeListingService.class); + + private static final String XPATH_THEME_NAME = "/theme/@name"; + + protected Document doProcess( + Document data, + GlobalContext context, + CallMeta callMeta + ) { + logger.debug("ThemeListingService.process"); + String name = XMLUtils.xpathString(data, XPATH_THEME_NAME, null); + + if (name == null) { + logger.warn("No theme name provided."); + } + Document result = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + null, + null); + + List<ThemeGroup> tgs = + ThemeFactory.getThemeGroups((FLYSContext) context); + + Element te = ec.create("themes"); + + for (ThemeGroup tg: tgs) { + Element elem = ec.create("themegroup"); + if (tg.getName().equals("virtual")) { + continue; + } + ec.addAttr(elem, "name", tg.getName()); + Theme theme = tg.getThemeByName(name); + Document d = theme.toXML(); + Node imported = result.importNode(d.getDocumentElement(), true); + elem.appendChild(imported); + te.appendChild(elem); + } + + result.appendChild(te); + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/AnnotationRiverState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,63 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.AnnotationFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * The only state for an AnnotationArtifact (River is known). + */ +public class AnnotationRiverState +extends DefaultState +implements FacetTypes +{ + /** Developer-centric description of facet. */ + public static final String I18N_DESCRIPTION = "facet.longitudinal_section.annotations"; + + /** The logger that is used in this state. */ + private static final Logger logger = Logger.getLogger(AnnotationRiverState.class); + + + /** + * Add an AnnotationFacet to list of Facets. + * + * @param artifact Ignored. + * @param hash Ignored. + * @param context Ignored. + * @param meta CallMeta to be used for internationalization. + * @param facets List to add AnnotationFacet to. + * + * @return null. + */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("AnnotationRiverState.computeInit()"); + + AnnotationFacet facet = new AnnotationFacet( + 0, + LONGITUDINAL_ANNOTATION, + Resources.getMsg(meta, I18N_DESCRIPTION, I18N_DESCRIPTION)); + facets.add(facet); + + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/AreaCreationState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,86 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.AreaFacet; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.AreaArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; + + +/** Trivial state to create areafacets, no caching. */ +public class AreaCreationState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(AreaCreationState.class); + + + /** + * From this state can only be continued trivially. + */ + @Override + protected String getUIProvider() { + return "continue"; + } + + + /** Just reproduce the Facet. */ + protected Object compute( + FLYSArtifact areaArtifact, + CallContext cc, + String hash, + List<Facet> facets, + Object old + ) { + logger.debug("AreaCreationState.compute"); + + if (facets != null) { + AreaArtifact aArt = (AreaArtifact) areaArtifact; + + facets.add(new AreaFacet(0, aArt.getFacetName(), aArt.getAreaName())); + } + + // TODO use compute to exploit caching strategies. + + return null; + } + + + /** + */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((FLYSArtifact) artifact, context, hash, facets, old); + } + + + /** + * + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((FLYSArtifact) artifact, context, hash, facets, old); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,135 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class CalculationSelect extends DefaultState { + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(CalculationSelect.class); + + + public static final String FIELD_MODE = "calculation_mode"; + + /** Constant value for the reference line calculation. */ + public static final String CALCULATION_SURFACE_CURVE = + "calc.surface.curve"; + + /** Constant value for the differences calculation. */ + public static final String CALCULATION_DURATION_CURVE = + "calc.duration.curve"; + + /** Constant value for the flood map calculation. */ + public static final String CALCULATION_FLOOD_MAP = + "calc.flood.map"; + + /** Constant value for the profile calculation. */ + public static final String CALCULATION_DISCHARGE_LONGITUDINAL_CURVE = + "calc.discharge.longitudinal.section"; + + /** Constant value for the state discharge curve calculation. */ + public static final String CALCULATION_DISCHARGE_CURVE = + "calc.discharge.curve"; + + /** Constant value for the state w differences calculation. */ + public static final String CALCULATION_W_DIFFERENCES = + "calc.w.differences"; + + /** Constant value for the state reference curve calculation. */ + public static final String CALCULATION_REFERENCE_CURVE = + "calc.reference.curve"; + + /** Constant value for the historical discharge curve calculation. */ + public static final String CALCULATION_HISTORICAL_DISCHARGE_CURVE = + "calc.historical.discharge.curve"; + + /** An array that holds all available calculation modes. */ + public static final String[] CALCULATIONS = { + CALCULATION_SURFACE_CURVE, + CALCULATION_FLOOD_MAP, + CALCULATION_DISCHARGE_CURVE, + CALCULATION_HISTORICAL_DISCHARGE_CURVE, + CALCULATION_DURATION_CURVE, + CALCULATION_DISCHARGE_LONGITUDINAL_CURVE, + CALCULATION_W_DIFFERENCES, + CALCULATION_REFERENCE_CURVE }; + + + /** Error message that is thrown if no mode has been chosen. */ + public static final String ERROR_NO_CALCULATION_MODE = + "error_feed_no_calculation_mode"; + + /** Error message that is thrown if an invalid calculation mode has been + * chosen. */ + public static final String ERROR_INVALID_CALCULATION_MODE = + "error_feed_invalid_calculation_mode"; + + + public CalculationSelect() { + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] calcs = new Element[CALCULATIONS.length]; + + for (int i = 0; i < CALCULATIONS.length; ++i) { + String calc = CALCULATIONS[i]; + calcs[i] = createItem( + cr, new String[] { + Resources.getMsg(meta, calc, calc), + calc + }); + } + + return calcs; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("CalculationSelect.validate"); + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData data = getData(flys, FIELD_MODE); + String calc = (data != null) ? (String) data.getValue() : null; + + if (calc == null) { + throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE); + } + + calc = calc.trim().toLowerCase(); + + for (String mode: CALCULATIONS) { + if (mode.equals(calc)) { + return true; + } + } + + throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/CalculationSelectMinfo.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,109 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class CalculationSelectMinfo extends DefaultState { + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(CalculationSelectMinfo.class); + + + public static final String FIELD_MODE = "calculation_mode"; + + public static final String CALC_BED_MIDDLE = "calc.bed.middle"; + public static final String CALC_BED_DIFF = "calc.bed.diff"; + public static final String CALC_BED_QUALITY = "calc.bed.quality"; + public static final String CALC_SEDIMENT_LOAD = "calc.sediment.load"; + public static final String CALC_FLOW_VELOCITY = "calc.flow.velocity"; + public static final String CALC_SQ_RELATION = "calc.sq.relation"; + + /** An array that holds all available calculation modes. */ + public static final String[] CALCULATIONS = { + CALC_BED_MIDDLE, + CALC_BED_DIFF, + CALC_BED_QUALITY, + CALC_SEDIMENT_LOAD, + CALC_FLOW_VELOCITY, + CALC_SQ_RELATION + }; + + + /** Error message that is thrown if no mode has been chosen. */ + public static final String ERROR_NO_CALCULATION_MODE = + "error_feed_no_calculation_mode"; + + /** Error message that is thrown if an invalid calculation mode has been + * chosen. */ + public static final String ERROR_INVALID_CALCULATION_MODE = + "error_feed_invalid_calculation_mode"; + + + public CalculationSelectMinfo() { + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] calcs = new Element[CALCULATIONS.length]; + + for (int i = 0; i < CALCULATIONS.length; ++i) { + String calc = CALCULATIONS[i]; + calcs[i] = createItem( + cr, new String[] { + Resources.getMsg(meta, calc, calc), + calc + }); + } + + return calcs; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("CalculationSelect.validate"); + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData data = getData(flys, FIELD_MODE); + String calc = (data != null) ? (String) data.getValue() : null; + + if (calc == null) { + throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE); + } + + calc = calc.trim().toLowerCase(); + + for (String mode: CALCULATIONS) { + if (mode.equals(calc)) { + return true; + } + } + + throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,169 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ComputationRangeState +extends RangeState +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(ComputationRangeState.class); + + /** The name of the 'from' field. */ + public static final String FROM = "ld_from"; + + /** The name of the 'to' field. */ + public static final String TO = "ld_to"; + + /** The name of the 'step' field. */ + public static final String STEP = "ld_step"; + + /** The default step width. */ + public static final int DEFAULT_STEP = 100; + + + public ComputationRangeState() { + } + + + @Override + protected Element createData( + XMLUtils.ElementCreator cr, + Artifact artifact, + StateData data, + CallContext context) + { + Element select = ProtocolUtils.createArtNode( + cr, "select", null, null); + + cr.addAttr(select, "name", data.getName(), true); + + Element label = ProtocolUtils.createArtNode( + cr, "label", null, null); + + Element choices = ProtocolUtils.createArtNode( + cr, "choices", null, null); + + label.setTextContent(Resources.getMsg( + context.getMeta(), + data.getName(), + data.getName())); + + select.appendChild(label); + + return select; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + double[] minmax = getMinMax(artifact); + + double minVal = Double.MIN_VALUE; + double maxVal = Double.MAX_VALUE; + + if (minmax != null) { + minVal = minmax[0]; + maxVal = minmax[1]; + } + else { + logger.warn("Could not read min/max distance values!"); + } + + if (name.equals("ld_from")) { + Element min = createItem( + cr, + new String[] {"min", new Double(minVal).toString()}); + + return new Element[] { min }; + } + else if (name.equals("ld_to")) { + Element max = createItem( + cr, + new String[] {"max", new Double(maxVal).toString()}); + + return new Element[] { max }; + } + else { + Element step = createItem( + cr, + new String[] {"step", String.valueOf(getDefaultStep())}); + return new Element[] { step }; + } + + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } + + + @Override + protected double[] getMinMax(Artifact artifact) { + FLYSArtifact flysArtifact = (FLYSArtifact) artifact; + return FLYSUtils.getRiverMinMax(flysArtifact); + } + + + protected double getDefaultStep() { + return DEFAULT_STEP; + } + + + @Override + protected String getLowerField() { + return FROM; + } + + + @Override + protected String getUpperField() { + return TO; + } + + + @Override + protected String getStepField() { + return STEP; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,103 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.ChartArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WaterlevelFacet; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + +/** + * The final state that will be reached after the discharge curve calculation + * mode has been chosen. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ComputedDischargeCurveState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state.*/ + private static Logger logger = + Logger.getLogger(ComputedDischargeCurveState.class); + + public ComputedDischargeCurveState() { + } + + + /** + * Get computed discharge curve data from cache (if available) or + * compute anew. Create Waterlevel and DataFacets. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("ComputedDischargeCurveState.computeAdvance"); + if(artifact instanceof WINFOArtifact) { + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult)old + : winfo.getComputedDischargeCurveData(); + + WQKms [] wqkms = (WQKms [])res.getData(); + + if (facets != null && wqkms.length > 0) { + for (int i = 0; i < wqkms.length; ++i) { + + Object[] args = new Object[] { + FLYSUtils.getRiver(winfo).getName(), + wqkms[i].getName() + }; + + String name = Resources.getMsg( + context.getMeta(), + "chart.computed.discharge.curve.curve.label", + "", + args); + + facets.add(new WaterlevelFacet(i, COMPUTED_DISCHARGE_Q, name)); + facets.add(new WaterlevelFacet(i, AT, "AT data")); + } + + facets.add(new DataFacet(CSV, "CSV data")); + facets.add(new DataFacet(PDF, "PDF data")); + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + } + + return res; + } + else if(artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DGMSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,140 @@ +package de.intevation.flys.artifacts.states; + +import java.io.File; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.model.DGM; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.utils.FLYSUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DGMSelect extends DefaultState { + + private static final Logger logger = Logger.getLogger(DGMSelect.class); + + public static final String ERR_EMPTY = "error_no_dgm_selected"; + public static final String ERR_INVALID_DGM = "error_invalid_dgm_selected"; + public static final String ERR_BAD_DGM_RANGE = "error_bad_dgm_range"; + public static final String ERR_BAD_DGM_RIVER = "error_bad_dgm_river"; + + + @Override + protected String getUIProvider() { + return "dgm_datacage_panel"; + } + + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + creator.addAttr(itemElement, "label", getLabel(cc, value), true); + dataElement.appendChild(itemElement); + + return dataElement; + } + + + public static String getLabel(CallContext cc, String value) { + logger.debug("Create label for value: " + value); + + try { + DGM dgm = DGM.getDGM(Integer.parseInt(value)); + + File file = new File(dgm.getPath()); + return file.getName(); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse int value: '" + value + "'"); + } + + return ""; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + FLYSArtifact flys = (FLYSArtifact) artifact; + + DGM dgm = getDGM(flys); + + if (dgm == null) { + throw new IllegalArgumentException(ERR_INVALID_DGM); + } + + double l = dgm.getLower().doubleValue(); + double u = dgm.getUpper().doubleValue(); + + double[] range = FLYSUtils.getKmFromTo(flys); + + if (range[0] < l || range[0] > u || range[1] < l || range[1] > u) { + throw new IllegalArgumentException(ERR_BAD_DGM_RANGE); + } + + River selectedRiver = FLYSUtils.getRiver(flys); + River dgmRiver = dgm.getRiver(); + + if (selectedRiver != dgmRiver) { + throw new IllegalArgumentException(ERR_BAD_DGM_RIVER); + } + + return true; + } + + + /** + * Returns the DGM specified in the parameters of <i>flys</i>. + * + * @param flys The FLYSArtifact that knows the ID of a DGM. + * + * @throws IllegalArgumentException If the FLYSArtifact doesn't know the ID + * of a DGM. + * + * @return the DGM specified by FLYSArtifact's parameters. + */ + public static DGM getDGM(FLYSArtifact flys) + throws IllegalArgumentException + { + try { + Integer dgmId = flys.getDataAsInteger("dgm"); + if (dgmId == null) { + throw new IllegalArgumentException(ERR_EMPTY); + } + + logger.debug("Found selected dgm: '" + dgmId + "'"); + + return DGM.getDGM(dgmId); + } + catch (NumberFormatException nfe) { + throw new IllegalArgumentException(ERR_INVALID_DGM); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DefaultState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,474 @@ +package de.intevation.flys.artifacts.states; + +import java.text.NumberFormat; +import java.util.Locale; +import java.util.Map; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.ProtocolUtils; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifactdatabase.state.AbstractState; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class DefaultState extends AbstractState { + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(DefaultState.class); + + + /** Determines, if the DESCRIBE document should contain default values or + * not. */ + public static final boolean USE_DEFAULTS = + Boolean.getBoolean("flys.use.default.values"); + + /** The three possible compute types. */ + public static enum ComputeType { + FEED, ADVANCE, INIT + } + + + protected StateData getData(FLYSArtifact artifact, String name) { + return artifact.getData(name); + } + + + /** + * Append to a node and return xml description relevant for gui. + */ + public Element describeStatic( + Artifact artifact, + Document document, + Node root, + CallContext context, + String uuid) + { + ElementCreator creator = new ElementCreator( + document, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + CallMeta meta = context.getMeta(); + + String helpText = Resources.getMsg(meta, getHelpText(), getHelpText()); + + String label = Resources.getMsg(meta, getID(), getID()); + Element ui = ProtocolUtils.createArtNode( + creator, "state", + new String[] { "name", "uiprovider", "label", "helpText"}, + new String[] { getID(), getUIProvider(), label, helpText }); + + Map<String, StateData> theData = getData(); + if (theData == null) { + return ui; + } + + FLYSArtifact flys = (FLYSArtifact)artifact; + + for (String name: theData.keySet()) { + appendStaticData(flys, context, creator, ui, name); + } + + return ui; + } + + + protected void appendStaticData( + FLYSArtifact flys, + CallContext context, + ElementCreator cr, + Element ui, + String name + ) { + StateData data = getData(flys, name); + String value = (data != null) ? (String) data.getValue() : null; + + if (value == null) { + return; + } + + String type = data.getType(); + + if (logger.isDebugEnabled()) { + logger.debug( + "Append element " + type + "'" + + name + "' (" + value + ")"); + } + + Element e = createStaticData(flys, cr, context, name, value, type); + + ui.appendChild(e); + + } + + + /** + * Creates a <i>data</i> element used in the static part of the DESCRIBE + * document. + * + * @param creator The ElementCreator that is used to build new Elements. + * @param cc The CallContext object used for nested i18n retrieval. + * @param name The name of the data item. + * @param value The value as string. + * + * @return an Element. + */ + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + creator.addAttr( + itemElement, + "label", + getLabelFor(cc, name, value, type), + true); + + dataElement.appendChild(itemElement); + + return dataElement; + } + + + /** + * @param cc + * @param name + * @param value + * @param type + * + * @return + */ + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + CallMeta meta = cc.getMeta(); + + try { + // XXX A better way to format the output would be to use the + // 'type' value of the data objects. + double doubleVal = Double.parseDouble(value); + Locale l = Resources.getLocale(meta); + NumberFormat nf = NumberFormat.getInstance(l); + + return nf.format(doubleVal); + } + catch (NumberFormatException nfe) { + return Resources.getMsg(meta, value, value); + } + } + + + /** + * This method returns the default value and description for <i>data</i>. + * Note, that this method returns the defaults only if <i>USE_DEFAULTS</i> + * is set; otherwise, null is returned. + * @param context The CallContext used for i18n. + * @param data The data objects that the defaults are for. + * @return a String[] with [default value, default label]. + */ + protected String[] getDefaultsFor(CallContext context, StateData data) { + if (USE_DEFAULTS) { + String defValue = (String) data.getValue(); + String defDesc = null; + + if (defValue != null && defValue.length() > 0) { + defDesc = Resources.getMsg( + context.getMeta(), + defValue, + defValue); + } + + if (defValue != null && defDesc != null) { + return new String[] { defValue, defDesc }; + } + } + + return null; + } + + + public Element describe( + Artifact artifact, + Document document, + Node root, + CallContext context, + String uuid) + { + ElementCreator creator = new ElementCreator( + document, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + String helpText = Resources.getMsg( + context.getMeta(), getHelpText(), getHelpText()); + + Element ui = null; + String uiprovider = getUIProvider(); + if (uiprovider != null) { + ui = ProtocolUtils.createArtNode( + creator, "dynamic", + new String[] { "uiprovider", "helpText" }, + new String[] { uiprovider, helpText }); + } + else { + ui = ProtocolUtils.createArtNode( + creator, "dynamic", + new String[] { "helpText" }, + new String[] { helpText }); + } + + Map<String, StateData> theData = getData(); + if (theData == null) { + return ui; + } + + FLYSArtifact flys = (FLYSArtifact)artifact; + + for (String name: theData.keySet()) { + StateData data = getData(flys, name); + + if (data == null) { + data = getData(name); + } + + Element select = createData(creator, artifact, data, context); + + String[] defaults = getDefaultsFor(context, data); + if (defaults != null && defaults.length > 1) { + creator.addAttr(select, "defaultValue", defaults[0], true); + creator.addAttr(select, "defaultLabel", defaults[1], true); + } + + appendItems(artifact, creator, name, context, select); + ui.appendChild(select); + } + + return ui; + } + + + /** + * @param artifact + * @param creator + * @param name + * @param context + * @param select + */ + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + Element choices = ProtocolUtils.createArtNode( + creator, "choices", null, null); + + select.appendChild(choices); + + Element[] items = createItems(creator, artifact, name, context); + if (items != null) { + for (Element item: items) { + choices.appendChild(item); + } + } + } + + + /** + * This method creates the root node that contains the list of selectable + * items. + * + * @param cr The ElementCreator. + * + * @return the root node of the item list. + */ + protected Element createData( + ElementCreator cr, + Artifact artifact, + StateData data, + CallContext context) + { + Element select = ProtocolUtils.createArtNode( + cr, "select", null, null); + cr.addAttr(select, "name", data.getName(), true); + + Element label = ProtocolUtils.createArtNode( + cr, "label", null, null); + + select.appendChild(label); + + label.setTextContent(Resources.getMsg( + context.getMeta(), + getID(), + getID())); + + return select; + } + + + /** + * This method creates a list of items. These items represent the amount of + * input data that is possible for this state. + * + * @param cr The ElementCreator. + * @param name The name of the amount of data. + * + * @return a list of items. + */ + protected Element[] createItems( + ElementCreator cr, + Artifact artifact, + String name, + CallContext context + ) { + return null; + } + + + /** + * This method is used to create an <i>item</i> Element that contains two + * further elements <i>label</i> and <i>value</i>. The label and value + * elements both have text nodes. + * + * @param cr The ElementCreator used to build new Elements. + * @param obj This implementation awaits a String array with [0] = label and + * [1] = value. + * + * @return an Element. + */ + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } + + + /** + * This method transform a given value into a StateData object. + * + * @param flys The FLYSArtifact. + * @param name The name of the data object. + * @param val The value of the data object. + * + * @return a StateData object with <i>name</i> and <i>val</i>ue. + */ + public StateData transform( + FLYSArtifact flys, + CallContext cc, + StateData stateData, + String name, + String val + ) { + if (logger.isDebugEnabled()) { + logger.debug("Transform data ('" + name + "','" + val + "')"); + } + + stateData.setValue(val); + + return stateData; + } + + + /** + * This method validates the inserted data and returns true, if everything + * was correct, otherwise an exception is thrown. + * + * @param artifact A reference to the owner artifact. + * + * @return true, if everything was fine. + */ + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + return true; + } + + + /** + * Returns which UIProvider shall be used to aid user input. + */ + protected String getUIProvider() { + return null; + } + + + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return null; + } + + + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return null; + } + + + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets) + { + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,117 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.ChartArtifact; + +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WaterlevelFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; + +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.model.DataFacet; + +public class DischargeLongitudinalSection +extends DefaultState +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(DischargeLongitudinalSection.class); + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult)old + : winfo.getDischargeLongitudinalSectionData(); + + if (facets == null) { + return res; + } + + WQKms [] wqkms = (WQKms [])res.getData(); + + for (int i = 0; i < wqkms.length; i++) { + String nameW = null; + String nameQ = null; + + if (winfo.isQ()) { + nameQ = wqkms[i].getName(); + nameW = "W(" + nameQ + ")"; + } + else { + nameW = wqkms[i].getName(); + nameQ = "Q(" + nameW + ")"; + } + + Facet w = new WaterlevelFacet( + i, DISCHARGE_LONGITUDINAL_W, nameW); + + Facet q = new WaterlevelFacet( + i, DISCHARGE_LONGITUDINAL_Q, nameQ); + + Facet s = new CrossSectionWaterLineFacet(i, nameW); + + facets.add(s); + facets.add(w); + facets.add(q); + + if (wqkms[i] instanceof WQCKms) { + // TODO DO i18n + + String nameC = nameW.replace( + "benutzerdefiniert", + "benutzerdefiniert [korrigiert]"); + + Facet c = new WaterlevelFacet( + i, DISCHARGE_LONGITUDINAL_C, nameC); + + // Here, avoid index clash with Facet "s" above and + // signal the WINFO later that we want to access Cs. + Facet r = new CrossSectionWaterLineFacet(i + 1, nameC); + + facets.add(c); + facets.add(r); + } + } + + if (wqkms.length > 0) { + facets.add(new DataFacet(CSV, "CSV data")); + facets.add(new DataFacet(WST, "WST data")); + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,160 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.model.KVP; + +import de.intevation.flys.model.DischargeZone; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.utils.FLYSUtils; + + +public class DischargeState extends MultiIntArrayState { + + public static final String MAIN_CHANNEL = "main_channel"; + public static final String TOTAL_CHANNEL = "total_channel"; + + + private static final Logger logger = Logger.getLogger(DischargeState.class); + + + @Override + public String getUIProvider() { + return "parameter-matrix"; + } + + + /** + * This method fetches all DischargeZones for a given river (extracted from + * <i>artifact</i>) and returns a KVP[] where the key is the ID of the + * DischargeZone and the value is a string that consists of lower discharge + * and upper discharge. + * + * @param artifact Needs to be a FLYSArtifact that provides river + * information. + * @param parameterName The name of a parameter. + * + * @return a KVP[]. + */ + @Override + protected KVP<Integer, String>[] getOptions( + Artifact artifact, + String parameterName + ) + throws IllegalArgumentException + { + if (!testParameterName(parameterName)) { + throw new IllegalArgumentException( + "Invalid parameter for state: '" + parameterName + "'"); + } + + List<DischargeZone> zones = getDischargeZones(artifact); + + KVP[] kvp = new KVP[zones.size()]; + + for (int i = 0, Z = zones.size(); i < Z; i++) { + DischargeZone zone = zones.get(i); + + String lower = zone.getLowerDischarge(); + String upper = zone.getUpperDischarge(); + + if (lower.equals(upper)) { + kvp[i] = new KVP(zone.getId(), lower); + } + else { + kvp[i] = new KVP(zone.getId(), lower + " - " + upper); + } + } + + return kvp; + } + + + @Override + protected String getLabelFor( + CallContext cc, + String parameterName, + int value + ) throws IllegalArgumentException + { + if (!testParameterName(parameterName)) { + throw new IllegalArgumentException( + "Invalid parameter for state: '" + parameterName + "'"); + } + + DischargeZone zone = DischargeZone.getDischargeZoneById(value); + + if (zone == null) { + throw new IllegalArgumentException( + "Invalid id for DischargeZone: '" + value + "'"); + } + + String lo = zone.getLowerDischarge(); + String hi = zone.getUpperDischarge(); + + return hi != null && lo.equals(hi) + ? lo + " - " + hi + : lo; + } + + + /** + * This method might be used to test, if a parameter name is handled by this + * state. + * + * @param parameterName The name of a parameter. + * + * @return true, if parameterName is one of <i>MAIN_CHANNEL</i> or + * <i>TOTAL_CHANNEL</i>. Otherwise false. + */ + protected boolean testParameterName(String parameterName) { + if (parameterName == null || parameterName.length() == 0) { + return false; + } + else if (parameterName.equals(MAIN_CHANNEL)) { + return true; + } + else if (parameterName.equals(TOTAL_CHANNEL)) { + return true; + } + else { + return false; + } + } + + + /** + * Returns all discharge zones for a given river. The river information is + * extracted from <i>artifact</i> using FLYSUtils.getRiver(). + * + * @param artifact Needs to be a FLYSArtifact that stores a rivername. + * + * @return a list of DischargeZones. + * + * @throws IllegalArgumentException if no river information is provided by + * <i>artifact</i>. + */ + protected List<DischargeZone> getDischargeZones(Artifact artifact) + throws IllegalArgumentException + { + River river = FLYSUtils.getRiver((FLYSArtifact) artifact); + + if (river == null) { + throw new IllegalArgumentException("No river found"); + } + + List<DischargeZone> zones = DischargeZone.getDischargeZones(river); + + logger.debug("Found " + zones.size() + " DischargeZones."); + + return zones; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DistanceOnlySelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,51 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +public class DistanceOnlySelect extends DistanceSelect { + + private static Logger logger = Logger.getLogger(DistanceOnlySelect.class); + + @Override + protected String getUIProvider() { + return "distance_only_panel"; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData dFrom = getData(flys, getLowerField()); + StateData dTo = getData(flys, getUpperField()); + + String fromStr = dFrom != null ? (String) dFrom.getValue() : null; + String toStr = dTo != null ? (String) dTo.getValue() : null; + + if (fromStr == null || toStr == null) { + throw new IllegalArgumentException("error_empty_state"); + } + + try { + double from = Double.parseDouble(fromStr); + double to = Double.parseDouble(toStr); + + double[] minmax = getMinMax(flys); + + return validateBounds(minmax[0], minmax[1], from, to); + } + catch (NumberFormatException nfe) { + throw new IllegalArgumentException("error_invalid_double_value"); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DistanceSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,24 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DistanceSelect extends ComputationRangeState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(DistanceSelect.class); + + + public DistanceSelect() { + } + + + @Override + protected String getUIProvider() { + return "distance_panel"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,111 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.ChartArtifact; + +import de.intevation.flys.artifacts.model.DurationCurveFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQDay; + +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * The final state that will be reached after the duration curve calculation + * mode has been chosen. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DurationCurveState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(DurationCurveState.class); + + public DurationCurveState() { + } + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof WINFOArtifact) { + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult res; + + if (old instanceof CalculationResult) { + res = (CalculationResult)old; + } + else { + res = winfo.getDurationCurveData(); + } + + WQDay wqday = (WQDay)res.getData(); + + if (wqday != null && facets != null) { + // Create an i18ed name for a (w or q) duration curve facet. + Object[] args = new Object[] { + FLYSUtils.getRiver(winfo).getName(), + FLYSUtils.getLocations(winfo)[0] + }; + + String nameW = Resources.getMsg( + context.getMeta(), + "chart.duration.curve.curve.w", + "", + args); + + String nameQ = Resources.getMsg( + context.getMeta(), + "chart.duration.curve.curve.q", + "", + args); + + Facet w = new DurationCurveFacet(DURATION_W, nameW); + Facet q = new DurationCurveFacet(DURATION_Q, nameQ); + + facets.add(w); + facets.add(q); + + facets.add(new DataFacet(CSV, "CSV data")); + facets.add(new DataFacet(PDF, "PDF data")); + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + } + + return res; + } + else if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,41 @@ +package de.intevation.flys.artifacts.states; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * Get me a double (km). + */ +public class EnterLocationState extends InputDoubleState { + + /** Provoke this kind of provider in the UI. */ + @Override + protected String getUIProvider() { + return "location_panel"; + } + + + /** Allow from min km of river. */ + @Override + protected Object getLower(FLYSArtifact flys) { + double[] lowerUpper = FLYSUtils.getRiverMinMax(flys); + + return lowerUpper != null + ? lowerUpper[0] + : 0; + } + + + /** Allow to max km of river. */ + @Override + protected Object getUpper(FLYSArtifact flys) { + double[] lowerUpper = FLYSUtils.getRiverMinMax(flys); + + return lowerUpper != null + ? lowerUpper[1] + : 0; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.StringUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.artifacts.WINFOArtifact; + + +/** + * Get me doubles (km). + */ +public class EnterMultipleLocationsState extends EnterLocationState { + /** The logger for this class. */ + private static Logger logger = Logger.getLogger(EnterMultipleLocationsState.class); + + @Override + protected String getUIProvider() { + logger.debug("multi location panel"); + return "multi_location_panel"; + } + + + /** Deal with multiple double values. */ + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + String label = ""; + String[] vals = value.split(" "); + for (int i = 0; i < vals.length; i++) { + vals[i] = super.getLabelFor(cc, name, vals[i], type); + } + + return StringUtils.join(" ", vals); + } + + /** + * This method creates a list of items. These items represent the amount of + * input data that is possible for this state. + * + * @param cr The ElementCreator. + * @param name The name of the amount of data. + * + * @return a list of items. + */ + @Override + protected Element[] createItems( + ElementCreator cr, + Artifact artifact, + String name, + CallContext context + ) { + if (name.equals("reference_endpoint")) { + Element[] elements = new Element[1]; + WINFOArtifact winfo = (WINFOArtifact) artifact; + Double km = winfo.getReferenceStartKm(); + elements[0] = createItem( + cr, + new String[] {"start_km", km.toString()}); + return elements; + } + return null; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,872 @@ +package de.intevation.flys.artifacts.states; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureCollections; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Polygon; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.GlobalContext; +import de.intevation.artifacts.common.utils.FileTools; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.model.CalculationMessage; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.map.WMSLayerFacet; +import de.intevation.flys.artifacts.model.map.WSPLGENCalculation; +import de.intevation.flys.artifacts.model.map.WSPLGENJob; +import de.intevation.flys.artifacts.model.map.WSPLGENReportFacet; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.exports.WstWriter; +import de.intevation.flys.model.CrossSectionTrack; +import de.intevation.flys.model.DGM; +import de.intevation.flys.model.Floodplain; +import de.intevation.flys.model.RiverAxis; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; +import de.intevation.flys.utils.MapfileGenerator; +import de.intevation.flys.wsplgen.FacetCreator; +import de.intevation.flys.wsplgen.JobObserver; +import de.intevation.flys.wsplgen.Scheduler; + + +public class FloodMapState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(FloodMapState.class); + + + public static final String KEEP_ARTIFACT_DIR = + System.getProperty("flys.uesk.keep.artifactsdir", "false"); + + + public static final String OUTPUT_NAME = "floodmap"; + + public static final String WSP_ARTIFACT = "wsp"; + + public static final String WINFO_WSP_STATE_ID = "state.winfo.waterlevel"; + + public static final String WSPLGEN_PARAMETER_FILE = "wsplgen.par"; + public static final String WSPLGEN_BARRIERS_LINES = "barrier_lines.shp"; + public static final String WSPLGEN_BARRIERS_POLY = "barrier_polygons.shp"; + public static final String WSPLGEN_AXIS = "axis.shp"; + public static final String WSPLGEN_QPS = "qps.shp"; + public static final String WSPLGEN_FLOODPLAIN = "talaue.shp"; + public static final String WSPLGEN_WSP_FILE = "waterlevel.wst"; + public static final String WSPLGEN_OUTPUT_FILE = "wsplgen.shp"; + public static final String WSPLGEN_USER_SHAPE = "user-rgd.shp"; + public static final String WSPLGEN_USER_ZIP = "user-rgd.zip"; + public static final String WSPLGEN_USER_FILENAME = "user-rgd"; + + public static final String WSPLGEN_QPS_NAME = "qps"; + + public static final int WSPLGEN_DEFAULT_OUTPUT = 0; + + + /** + * @param orig + * @param owner + * @param context + * @param callMeta + */ + @Override + public void initialize( + Artifact orig, + Artifact owner, + Object context, + CallMeta callMeta + ) { + logger.info("Initialize State with Artifact: " + orig.identifier()); + + copyShapeDir(orig, owner); + modifyFacets(orig, owner, context, callMeta); + + MapfileGenerator.getInstance().update(); + } + + + protected void copyShapeDir(Artifact orig, Artifact owner) { + File origDir = getDirectory((FLYSArtifact) orig); + File thisDir = getDirectory((FLYSArtifact) owner); + + FileTools.copyDirectory(origDir, thisDir); + } + + + protected void modifyFacets( + Artifact orig, + Artifact owner, + Object context, + CallMeta callMeta + ) { + FLYSArtifact flys = (FLYSArtifact) owner; + List<Facet> facets = flys.getFacets(); + if (facets == null || facets.isEmpty()) { + logger.warn("No facets for '" + OUTPUT_NAME + "' given!"); + return; + } + + for (Facet facet: facets) { + if (facet instanceof WMSLayerFacet) { + WMSLayerFacet wms = (WMSLayerFacet) facet; + + List<String> layers = wms.getLayers(); + + for (String layer: layers) { + if (layer.startsWith(MapfileGenerator.MS_WSPLGEN_PREFIX)) { + wms.removeLayer(layer); + + String newLayer = MapfileGenerator.MS_WSPLGEN_PREFIX + + owner.identifier(); + + wms.addLayer(newLayer); + + logger.debug( + "Replaced layer: " + layer + " with " + newLayer); + } + } + } + } + } + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("FloodMapState.computeAdvance"); + + File artifactDir = getDirectory(artifact); + + if (artifactDir == null) { + logger.error("Could not create directory for WSPLGEN results!"); + return null; + } + + WSPLGENCalculation calculation = new WSPLGENCalculation(); + + FacetCreator facetCreator = new FacetCreator( + artifact, context, hash, getID(), facets); + + WSPLGENJob job = prepareWSPLGENJob( + artifact, + facetCreator, + artifactDir, + context, + calculation); + + CalculationResult res = new CalculationResult(null, calculation); + WSPLGENReportFacet report= new WSPLGENReportFacet( + ComputeType.ADVANCE, hash, getID(), res); + + facets.add(report); + + if (job == null) { + if (KEEP_ARTIFACT_DIR.equals("false")) { + removeDirectory(artifact); + } + + calculation.addError(-1, Resources.getMsg( + context.getMeta(), + "wsplgen.job.error", + "wsplgen.job.error")); + + logger.error("No WSPLGEN processing has been started!"); + + return null; + } + + context.afterCall(CallContext.BACKGROUND); + context.addBackgroundMessage(new CalculationMessage( + JobObserver.STEPS.length, + 0, + Resources.getMsg( + context.getMeta(), + "wsplgen.job.queued", + "wsplgen.job.queued") + )); + + GlobalContext gc = (GlobalContext) context.globalContext(); + Scheduler scheduler = (Scheduler) gc.get(FLYSContext.SCHEDULER); + scheduler.addJob(job); + + return null; + } + + + /** + * Returns (and creates if not existing) the directory for storing WSPLEN + * data for the owner artifact. + * + * @param artifact The owner Artifact. + * + * @return the directory for WSPLEN data. + */ + protected File getDirectory(FLYSArtifact artifact) { + String shapePath = FLYSUtils.getXPathString( + FLYSUtils.XPATH_SHAPEFILE_DIR); + + File artifactDir = FileTools.getDirectory( + shapePath, artifact.identifier()); + + return artifactDir; + } + + + /** + * Removes the directory and all its content where the required data and the + * results of WSPLGEN are stored. Should be called in endOfLife(). + */ + protected void removeDirectory(FLYSArtifact artifact) { + String shapePath = FLYSUtils.getXPathString( + FLYSUtils.XPATH_SHAPEFILE_DIR); + + File artifactDir = new File(shapePath, artifact.identifier()); + + if (artifactDir.exists()) { + logger.info("Delete directory: " + artifactDir.getAbsolutePath()); + boolean success = FileTools.deleteRecursive(artifactDir); + } + else { + logger.debug("There is no directory to remove."); + } + } + + + @Override + public void endOfLife(Artifact artifact, Object callContext) { + logger.info("FloodMapState.endOfLife: " + artifact.identifier()); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + Scheduler scheduler = Scheduler.getInstance(); + scheduler.cancelJob(flys.identifier()); + + MapfileGenerator.getInstance().update(); + } + + + protected WSPLGENJob prepareWSPLGENJob( + FLYSArtifact artifact, + FacetCreator facetCreator, + File artifactDir, + CallContext context, + WSPLGENCalculation calculation + ) { + logger.debug("FloodMapState.prepareWSPLGENJob"); + + WSPLGENJob job = new WSPLGENJob( + artifact, + artifactDir, + facetCreator, + context, + calculation); + + File paraFile = new File(artifactDir, WSPLGEN_PARAMETER_FILE); + + setOut(artifact, job); + setRange(artifact, job); + setDelta(artifact, job); + setGel(artifact, job); + setDist(artifact, job); + setLine(artifact, facetCreator, artifactDir, job); + setUserShape(artifact, facetCreator, artifactDir, job); + setAxis(artifact, artifactDir, job); + setPro(artifact, artifactDir, job); + setDgm(artifact, job); + setArea(artifact, artifactDir, job); + setOutFile(artifact, job); + setWsp(artifact, context, artifactDir, job); // WSP + + // TODO + // setWspTag(artifact, job); + + try { + job.toFile(paraFile); + + return job; + } + catch (IOException ioe) { + logger.warn("Cannot write PAR file: " + ioe.getMessage()); + } + catch (IllegalArgumentException iae) { + logger.warn("Cannot write PAR file: " + iae.getMessage()); + } + + return null; + } + + + protected void setOut(FLYSArtifact artifact, WSPLGENJob job) { + job.setOut(WSPLGEN_DEFAULT_OUTPUT); + } + + + protected void setRange(FLYSArtifact artifact, WSPLGENJob job) { + double[] range = FLYSUtils.getKmRange(artifact); + + job.setStart(range[0]); + job.setEnd(range[1]); + } + + + protected void setDelta(FLYSArtifact artifact, WSPLGENJob job) { + String from = artifact.getDataAsString("diff_from"); + String to = artifact.getDataAsString("diff_to"); + String diff = artifact.getDataAsString("diff_diff"); + + try { + job.setFrom(Double.parseDouble(from)); + } + catch (NumberFormatException nfe) { + } + + try { + job.setTo(Double.parseDouble(to)); + } + catch (NumberFormatException nfe) { + } + + try { + job.setDiff(Double.parseDouble(diff)); + } + catch (NumberFormatException nfe) { + } + } + + + protected void setGel(FLYSArtifact artifact, WSPLGENJob job) { + String gel = artifact.getDataAsString("scenario"); + + logger.debug("Selected gel = '" + gel + "'"); + + if (gel == null || gel.length() == 0) { + job.setGel(WSPLGENJob.GEL_NOSPERRE); + } + else if (gel.equals("scenario.current")) { + job.setGel(WSPLGENJob.GEL_SPERRE); + } + else if (gel.equals("scenario.scenario")) { + job.setGel(WSPLGENJob.GEL_SPERRE); + } + else { + job.setGel(WSPLGENJob.GEL_NOSPERRE); + } + } + + + protected void setDist(FLYSArtifact artifact, WSPLGENJob job) { + String dist = artifact.getDataAsString("profile_distance"); + + try { + job.setDist(Double.parseDouble(dist)); + } + catch (NumberFormatException nfe) { + // nothing to do here + } + } + + + protected void setLine( + FLYSArtifact artifact, + FacetCreator facetCreator, + File dir, + WSPLGENJob job + ) { + String geoJSON = artifact.getDataAsString("uesk.barriers"); + String srid = FLYSUtils.getRiverSrid(artifact); + String srs = "EPSG:" + srid; + + if (geoJSON == null || geoJSON.length() == 0) { + logger.debug("No barrier features in parameterization existing."); + return; + } + + SimpleFeatureType ft = getBarriersFeatureType( + "barriers", srs, Geometry.class); + + List<SimpleFeature> features = GeometryUtils.parseGeoJSON(geoJSON, ft); + if (features == null || features.isEmpty()) { + logger.debug("No barrier features extracted."); + return; + } + + FeatureCollection[] fcs = splitLinesAndPolygons(features); + + File shapeLines = new File(dir, WSPLGEN_BARRIERS_LINES); + File shapePolys = new File(dir, WSPLGEN_BARRIERS_POLY); + + Object[][] obj = new Object[][] { + new Object[] { "typ", String.class } + }; + + String scenario = job.getGel(); + + boolean l = GeometryUtils.writeShapefile( + shapeLines, + GeometryUtils.buildFeatureType("lines", srs, LineString.class, obj), + fcs[0]); + + if (l) { + logger.debug( + "Successfully created barrier line shapefile. " + + "Write shapefile path into WSPLGEN job."); + + if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) { + logger.debug("WSPLGEN will not use barrier features."); + } + else { + job.addLin(shapeLines.getAbsolutePath()); + } + } + + boolean p = GeometryUtils.writeShapefile( + shapePolys, + GeometryUtils.buildFeatureType("polygons", srs, Polygon.class, obj), + fcs[1]); + + if (p) { + logger.debug( + "Successfully created barrier polygon shapefile. " + + "Write shapefile path into WSPLGEN job."); + + if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) { + logger.debug("WSPLGEN will not use barrier features."); + } + else { + job.addLin(shapePolys.getAbsolutePath()); + } + } + + if (p || l) { + facetCreator.createBarrierFacet(); + } + } + + + protected void setUserShape( + FLYSArtifact artifact, + FacetCreator facetCreator, + File dir, + WSPLGENJob job + ) { + File archive = new File(dir, WSPLGEN_USER_ZIP); + boolean exists = archive.exists(); + logger.debug("Zip file exists: " + exists); + if (exists) { + try { + File tmpDir = new File(dir, "usr_tmp"); + FileTools.extractArchive(archive, tmpDir); + moveFiles(tmpDir, dir); + } + catch (IOException ioe) { + logger.warn("Zip archive " + dir + "/" + WSPLGEN_USER_ZIP + " could not be extracted."); + return; + } + + job.addLin(dir + "/" + WSPLGEN_USER_SHAPE); + facetCreator.createUserShapeFacet(); + } + } + + protected SimpleFeatureType getBarriersFeatureType( + String name, + String srs, + Class type + ) { + Object[][] attrs = new Object[3][]; + attrs[0] = new Object[] { "typ", String.class }; + attrs[1] = new Object[] { "elevation", Double.class }; + attrs[2] = new Object[] { "mark.selected", Integer.class }; + + return GeometryUtils.buildFeatureType(name, srs, type, attrs); + } + + + protected FeatureCollection[] splitLinesAndPolygons(List<SimpleFeature> f) { + FeatureCollection lines = FeatureCollections.newCollection(); + FeatureCollection polygons = FeatureCollections.newCollection(); + + for (SimpleFeature feature: f) { + Geometry geom = (Geometry) feature.getDefaultGeometry(); + + + if (geom instanceof LineString) { + geom = applyElevationAttribute(feature, (LineString) geom); + lines.add(feature); + } + else if (geom instanceof Polygon) { + geom = applyElevationAttribute(feature, (Polygon) geom); + polygons.add(feature); + } + else { + logger.warn("Feature not supported: " + geom.getClass()); + } + } + + logger.debug("Found " + lines.size() + " barrier lines."); + logger.debug("Found " + polygons.size() + " barrier polygons."); + + return new FeatureCollection[] { lines, polygons }; + } + + + protected static Geometry applyElevationAttribute( + SimpleFeature feature, + Geometry geom + ) { + logger.debug("Apply elevations for: " + geom.getClass()); + + List<Double> elevations = extractElevations(feature); + int numPoints = geom.getNumPoints(); + int numElevation = elevations.size(); + + String typ = (String) feature.getAttribute("typ"); + + if (numPoints > numElevation) { + logger.warn("More vertices in Geometry than elevations given."); + } + + Coordinate[] c = geom.getCoordinates(); + for (int i = 0; i < numPoints; i++) { + if (i < numElevation) { + c[i].z = elevations.get(i); + } + else if (typ != null && typ.equals("Graben")) { + c[i].z = -9999d; + } + else { + c[i].z = 9999d; + } + } + + return geom; + } + + + protected static List<Double> extractElevations(SimpleFeature feature) { + String tmp = (String) feature.getAttribute("elevation"); + String typ = (String) feature.getAttribute("typ"); + + String[] elevations = tmp == null ? null : tmp.split(" "); + + int num = elevations != null ? elevations.length : 0; + + List<Double> list = new ArrayList<Double>(num); + + for (int i = 0; i < num; i++) { + try { + list.add(Double.parseDouble(elevations[i])); + } + catch (NumberFormatException nfe) { + logger.warn("Error while parsing elevation at pos: " + i); + if (typ != null && typ.equals("Graben")) { + list.add(new Double(-9999.0)); + } + else { + list.add(new Double(9999.0)); + } + } + } + + return list; + } + + + protected void setAxis(FLYSArtifact artifact, File dir, WSPLGENJob job) { + String river = artifact.getDataAsString("river"); + String srid = FLYSUtils.getRiverSrid(artifact); + String srs = "EPSG:" + srid; + + List<RiverAxis> axes = RiverAxis.getRiverAxis(river); + if (axes == null || axes.isEmpty()) { + logger.warn("Could not find river axis for: '" + river + "'"); + return; + } + + SimpleFeatureType ft = GeometryUtils.buildFeatureType( + "axis", srs, LineString.class); + + SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft); + FeatureCollection collection = FeatureCollections.newCollection(); + + for (int i = 0, n = axes.size(); i < n; i++) { + RiverAxis axis = axes.get(i); + + builder.add(axis.getGeom()); + collection.add(builder.buildFeature(String.valueOf(i))); + + builder.reset(); + } + + File axisShape = new File(dir, WSPLGEN_AXIS); + + boolean a = GeometryUtils.writeShapefile( + axisShape, + GeometryUtils.buildFeatureType("axis", srs, LineString.class), + collection); + + if (a) { + job.setAxis(axisShape.getAbsolutePath()); + } + } + + + protected void setPro(FLYSArtifact artifact, File dir, WSPLGENJob job) { + String river = artifact.getDataAsString("river"); + String srid = FLYSUtils.getRiverSrid(artifact); + String srs = "EPSG:" + srid; + + List<CrossSectionTrack> cst = + CrossSectionTrack.getCrossSectionTrack(river, WSPLGEN_QPS_NAME); + + logger.debug("Found " + cst.size() + " CrossSectionTracks."); + + Object[][] attrs = new Object[2][]; + attrs[0] = new Object[] { "ELEVATION", Double.class }; + attrs[1] = new Object[] { "KILOMETER", Double.class }; + + SimpleFeatureType ft = GeometryUtils.buildFeatureType( + "qps", srs, LineString.class, attrs); + + SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft); + FeatureCollection collection = FeatureCollections.newCollection(); + + int i = 0; + for (CrossSectionTrack track: cst) { + builder.reset(); + builder.add(track.getGeom()); + builder.add(track.getZ().doubleValue()); + builder.add(track.getKm().doubleValue()); + + collection.add(builder.buildFeature(String.valueOf(i++))); + } + + File qpsShape = new File(dir, WSPLGEN_QPS); + + boolean q = GeometryUtils.writeShapefile( + qpsShape, + GeometryUtils.buildFeatureType("qps", srs, LineString.class, attrs), + collection); + + if (q) { + job.setPro(qpsShape.getAbsolutePath()); + } + } + + + protected void setDgm(FLYSArtifact artifact, WSPLGENJob job) { + String dgm_id = artifact.getDataAsString("dgm"); + + int id = -1; + try { + id = Integer.parseInt(dgm_id); + } + catch (NumberFormatException nfe) { /* do nothing */ } + + DGM dgm = DGM.getDGM(id); + + if (dgm == null) { + logger.warn("Could not find specified DGM."); + + return; + } + + job.setDgm(dgm.getPath()); + } + + + protected void setArea(FLYSArtifact artifact, File dir, WSPLGENJob job) { + String useFloodplain = artifact.getDataAsString("use_floodplain"); + if (!Boolean.valueOf(useFloodplain)) { + logger.debug("WSPLGEN will not use floodplain."); + return; + } + + String river = artifact.getDataAsString("river"); + String srid = FLYSUtils.getRiverSrid(artifact); + String srs = "EPSG:" + srid; + + Floodplain plain = Floodplain.getFloodplain(river); + + SimpleFeatureType ft = GeometryUtils.buildFeatureType( + "talaue", srs, Polygon.class); + + SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft); + builder.add(plain.getGeom()); + + FeatureCollection collection = FeatureCollections.newCollection(); + collection.add(builder.buildFeature("0")); + + File talaueShape = new File(dir, WSPLGEN_FLOODPLAIN); + + boolean t = GeometryUtils.writeShapefile( + talaueShape, + GeometryUtils.buildFeatureType("talaue", srs, Polygon.class), + collection); + + if (t) { + job.setArea(talaueShape.getAbsolutePath()); + } + } + + + protected void setOutFile(FLYSArtifact artifact, WSPLGENJob job) { + job.setOutFile(WSPLGEN_OUTPUT_FILE); + } + + + protected WQKms getWQKms(FLYSArtifact flys, CallContext cc) { + String wspString = flys.getDataAsString(WSP_ARTIFACT); + String[] parts = wspString.split(";"); + + String otherArtifact = parts[0]; + + int idx = -1; + try { + idx = Integer.parseInt(parts[2]); + } + catch (NumberFormatException nfe) { /* do nothing */ } + + FLYSArtifact src = otherArtifact != null + ? FLYSUtils.getArtifact(otherArtifact, cc) + : flys; + + logger.debug("Use waterlevel provided by Artifact: " + src.identifier()); + + CalculationResult rawData = (CalculationResult) src.compute( + cc, + null, + WINFO_WSP_STATE_ID, + ComputeType.ADVANCE, + false); + + WQKms[] wqkms = (WQKms[]) rawData.getData(); + + return wqkms == null || idx == -1 || idx >= wqkms.length + ? null + : wqkms[idx]; + } + + + protected void setWsp( + FLYSArtifact artifact, + CallContext context, + File dir, + WSPLGENJob job) + { + logger.debug("FloodMapState.setWsp"); + + WQKms data = getWQKms(artifact, context); + + if (data == null) { + logger.warn("No WST data found!"); + return; + } + + WstWriter writer = new WstWriter(1); + + // TODO REMOVE job.setWspTag(...) This is only used until the user is + // able to select the WSP column himself! + boolean writeWspTag = true; + + double[] buf = new double[4]; + logger.debug("Add WST column: " + data.getName()); + writer.addColumn(data.getName()); + + if (writeWspTag) { + job.setWspTag(data.getName()); + writeWspTag = false; + } + + for (int i = 0, num = data.size(); i < num; i++) { + data.get(i, buf); + writer.add(buf); + } + + FileOutputStream fout = null; + + try { + File wspFile = new File(dir, WSPLGEN_WSP_FILE); + fout = new FileOutputStream(wspFile); + + writer.write(fout); + + job.setWsp(wspFile.getAbsolutePath()); + } + catch (FileNotFoundException fnfe) { + logger.warn("Error while writing wsp file: " + fnfe.getMessage()); + } + finally { + if (fout != null) { + try { + fout.close(); + } + catch (IOException ioe) { /* do nothing */ } + } + } + } + + + protected void moveFiles(File source, final File target) + throws IOException + { + if (!source.exists()) { + return; + } + if (!target.exists()) { + target.mkdir(); + } + FileTools.walkTree(source, new FileTools.FileVisitor() { + public boolean visit(File file) { + if (!file.isDirectory()) { + String name = file.getName(); + String suffix = ""; + int pos = name.lastIndexOf('.'); + if (pos > 0 && pos < name.length() - 1) { + suffix = name.substring(pos + 1); + } + else { + return true; + } + try { + FileTools.copyFile(file, new File(target, WSPLGEN_USER_FILENAME + "." + suffix)); + } + catch (IOException ioe) { + logger.warn ("Error while copying file " + file.getName()); + return true; + } + } + return true; + } + }); + + FileTools.deleteRecursive(source); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,87 @@ +package de.intevation.flys.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.ProtocolUtils; + +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FloodplainChoice extends DefaultState { + + public static final String OPTION = "floodplain.option"; + public static final String ACTIVE = "floodplain.active"; + public static final String INACTIVE = "floodplain.inactive"; + + private static final Logger logger = + Logger.getLogger(FloodplainChoice.class); + + + @Override + protected String getUIProvider() { + return "boolean_panel"; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + + Element option = createItem( + cr, + new String[] { Resources.getMsg(meta, OPTION, OPTION), "true" }); + + return new Element[] { option }; + } + + + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + logger.debug("GET LABEL FOR '" + name + "' / '" + value + "'"); + if (value != null && value.equals("true")) { + return Resources.getMsg(cc.getMeta(), ACTIVE, ACTIVE); + } + else { + return Resources.getMsg(cc.getMeta(), INACTIVE, INACTIVE); + } + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,159 @@ +package de.intevation.flys.artifacts.states; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.FlowVelocityAccess; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.FlowVelocityCalculation; +import de.intevation.flys.artifacts.model.FlowVelocityData; +import de.intevation.flys.artifacts.model.FlowVelocityFacet; +import de.intevation.flys.artifacts.resources.Resources; + + +public class FlowVelocityState extends DefaultState implements FacetTypes { + + private static Logger logger = Logger.getLogger(FlowVelocityState.class); + + + public static final String I18N_MAINCHANNEL_FACET = + "facet.flow_velocity.mainchannel"; + + public static final String I18N_TOTALCHANNEL_FACET = + "facet.flow_velocity.totalchannel"; + + public static final String I18N_TAU_FACET = + "facet.flow_velocity.tauchannel"; + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("FlowVelocityState.computeAdvance"); + + List<Facet> newFacets = new ArrayList<Facet>(); + + FlowVelocityAccess access = new FlowVelocityAccess(artifact); + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult) old + : new FlowVelocityCalculation().calculate(access); + + if (facets == null || res == null) { + return res; + } + + FlowVelocityData[] data = (FlowVelocityData[]) res.getData(); + + logger.debug("Calculated " + data.length + " FlowVelocityData objects"); + + String id = getID(); + int idx = 0; + + for (FlowVelocityData d: data) { + logger.error("TODO: Implement Facet creation for chart!"); + + newFacets.add(new FlowVelocityFacet( + idx, + FLOW_VELOCITY_MAINCHANNEL, + buildMainChannelName(artifact, context, d), + ComputeType.ADVANCE, + id, + hash + )); + + newFacets.add(new FlowVelocityFacet( + idx, + FLOW_VELOCITY_TOTALCHANNEL, + buildTotalChannelName(artifact, context, d), + ComputeType.ADVANCE, + id, + hash + )); + + newFacets.add(new FlowVelocityFacet( + idx, + FLOW_VELOCITY_TAU, + buildTauName(artifact, context, d), + ComputeType.ADVANCE, + id, + hash + )); + + idx++; + } + + Facet csv = new DataFacet( + CSV, "CSV data", ComputeType.ADVANCE, hash, id); + + // TODO ADD PDF FACET + + newFacets.add(csv); + + logger.debug("Created " + newFacets.size() + " new Facets."); + + facets.addAll(newFacets); + + return res; + } + + + protected String buildFacetName( + FLYSArtifact flys, + CallContext cc, + FlowVelocityData data, + String resourceId + ) { + Object[] args = new Object[] { + data.getZone() + }; + + return Resources.getMsg( + cc.getMeta(), + resourceId, + resourceId, + args); + } + + + protected String buildMainChannelName( + FLYSArtifact flys, + CallContext cc, + FlowVelocityData data + ) { + return buildFacetName(flys, cc, data, I18N_MAINCHANNEL_FACET); + } + + + protected String buildTotalChannelName( + FLYSArtifact flys, + CallContext cc, + FlowVelocityData data + ) { + return buildFacetName(flys, cc, data, I18N_TOTALCHANNEL_FACET); + } + + + protected String buildTauName( + FLYSArtifact flys, + CallContext cc, + FlowVelocityData data + ) { + return buildFacetName(flys, cc, data, I18N_TAU_FACET); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,161 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.ChartArtifact; +import de.intevation.flys.artifacts.GaugeDischargeArtifact; +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.GaugeDischargeFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.model.Gauge; + + +/** + * The only state for an GaugeDischargeState (River and km known). + */ +public class GaugeDischargeState +extends DefaultState +implements FacetTypes +{ + /** Developer-centric description of facet. */ + public static final String I18N_DESCRIPTION = "facet.discharge.curve"; + + /** The logger that is used in this state. */ + private static final Logger logger = + Logger.getLogger(GaugeDischargeState.class); + + + /** + * Create i18ned name for gaugedischargeFacet. + * @param artifact The artifact which has information about the gauge. + * @param meta used for i18n. + * @return localized name for gaugedischargefacet. + */ + protected String createFacetName(GaugeDischargeArtifact artifact, + CallMeta meta) { + + Gauge gauge = artifact.getGauge(); + Object[] args = new Object[] { + gauge.getName(), + gauge.getStation() + }; + + String name = Resources.getMsg( + meta, + "chart.computed.discharge.curve.gauge", + "", + args); + + return name; + } + + + /** + * Add an GaugeDischargeFacet to list of Facets. + * + * @param artifact Ignored. + * @param hash Ignored. + * @param context Ignored. + * @param meta CallMeta to be used for internationalization. + * @param facets List to add AnnotationFacet to. + * + * @return null. + */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("GaugeDischargeState.computeInit()"); + + GaugeDischargeFacet facet = new GaugeDischargeFacet( + 0, + DISCHARGE_CURVE, + createFacetName((GaugeDischargeArtifact) artifact, meta)); + + facets.add(facet); + + return null; + } + + + /** + * 'Calculate' Discharge at Gauge. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof GaugeDischargeArtifact) { + logger.debug("GaugeDischargeState.computeAdvance()"); + GaugeDischargeArtifact dischargeArtifact = (GaugeDischargeArtifact) artifact; + + CalculationResult res; + + + if (old instanceof CalculationResult) { + res = (CalculationResult) old; + } + else { + res = dischargeArtifact.getDischargeCurveData(); + } + + WQKms[] wqkms = (WQKms[]) res.getData(); + + if (wqkms != null && facets != null) { + logger.debug("GaugeDischargeState.computeAdvance(): create facets"); + + GaugeDischargeFacet facet = new GaugeDischargeFacet( + 0, + DISCHARGE_CURVE, + createFacetName(dischargeArtifact, context.getMeta())); + + facets.add(facet); + + //facets.add(new DataFacet(CSV, "CSV data")); + //facets.add(new DataFacet(PDF, "PDF data")); + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + } + else { + if (wqkms == null) + logger.debug("GaugeDischargeState.computeAdvance(): wqkms 0"); + else + logger.debug("GaugeDischargeState.computeAdvance(): facets 0"); + } + + return res; + } + else if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,87 @@ +package de.intevation.flys.artifacts.states; + +import java.util.Calendar; +import java.util.List; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.utils.FLYSUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class GaugeTimerangeState extends IntRangeState { + + private static final Logger logger = + Logger.getLogger(GaugeTimerangeState.class); + + + protected int[] getLowerUpper(FLYSArtifact flys) { + Gauge gauge = FLYSUtils.getReferenceGauge(flys); + + if (gauge == null) { + logger.warn("No reference gauge specified!"); + return new int[] { 0, 0 }; + } + + Session session = SessionHolder.HOLDER.get(); + + SQLQuery query = session.createSQLQuery( + "SELECT min(start_time) as min, max(stop_time) as max " + + "FROM time_intervals WHERE id in " + + "(SELECT time_interval_id FROM discharge_tables " + + "WHERE gauge_id =:gid)"); + + query.addScalar("min", StandardBasicTypes.CALENDAR); + query.addScalar("max", StandardBasicTypes.CALENDAR); + + query.setInteger("gid", gauge.getId()); + + List<?> results = query.list(); + + if (results != null) { + Object[] res = (Object[]) results.get(0); + + Calendar lo = (Calendar) res[0]; + Calendar up = (Calendar) res[1]; + + if (lo != null && up != null) { + return new int[] { lo.get(Calendar.YEAR), up.get(Calendar.YEAR) }; + } + } + + logger.warn("Could not determine time range for gauge: " + gauge); + + return null; + } + + + @Override + protected Object getLower(FLYSArtifact flys) { + int[] lowerUpper = getLowerUpper(flys); + + return lowerUpper != null ? lowerUpper[0] : 0; + } + + + @Override + protected Object getUpper(FLYSArtifact flys) { + int[] lowerUpper = getLowerUpper(flys); + + return lowerUpper != null ? lowerUpper[1] : 0; + } + + + @Override + protected String getUIProvider() { + return "gaugetimerange"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,121 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.HistoricalDischargeFacet; +import de.intevation.flys.artifacts.model.HistoricalDischargeDifferenceFacet; +import de.intevation.flys.artifacts.model.HistoricalWQTimerange; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WQTimerange; + + +/** + * State to calculate historical discharge curves. + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeComputeState +extends DefaultState +implements FacetTypes +{ + + private static final Logger logger = + Logger.getLogger(HistoricalDischargeComputeState.class); + + + @Override + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + // TODO IMPLEMENT ME + } + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("HistoricalDischargeComputeState.computeAdvance"); + + WINFOArtifact winfo = (WINFOArtifact) artifact; + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult) old + : winfo.getHistoricalDischargeData(); + + if (facets == null) { + return res; + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + WQTimerange[] data = (WQTimerange[]) res.getData(); + if (data == null || data.length == 0) { + logger.warn("Historical Discharge calculation has no results!"); + return res; + } + + facets.add( + new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id)); + + facets.add( + new DataFacet(PDF, "PDF data", ComputeType.ADVANCE, hash, id)); + + prepareFacets(facets, data); + + return res; + } + + + protected void prepareFacets(List<Facet> facets, WQTimerange[] wqts) { + int i = 0; + + for (WQTimerange wqt: wqts) { + logger.debug("Prepare facet for: " + wqt.getName()); + + // TODO CREATE BETTER TITLE FOR FACETS + + facets.add(new HistoricalDischargeFacet( + i, + HISTORICAL_DISCHARGE_Q, + wqt.getName())); + + if (wqt instanceof HistoricalWQTimerange) { + logger.debug("Create another facet for historical differences."); + + facets.add(new HistoricalDischargeDifferenceFacet( + i, + HISTORICAL_DISCHARGE_Q_DIFF, + "DIFF: " + wqt.getName())); + } + + i++; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,152 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeState extends DefaultState { + + private static final Logger logger = + Logger.getLogger(HistoricalDischargeState.class); + + + public static final String I18N_MODE_W = "historical.mode.w"; + public static final String I18N_MODE_Q = "historical.mode.q"; + + public static final String DATA_MODE = "historical_mode"; + public static final String DATA_VALUES = "historical_values"; + public static final int DATA_MODE_W = 0; + public static final int DATA_MODE_Q = 1; + + + @Override + protected String getUIProvider() { + return "wq_simple_array"; + } + + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + if (name != null && name.equals(DATA_VALUES)) { + select.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "art:type", + "doublearray"); + } + else if (name != null && name.equals(DATA_MODE)) { + select.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "art:type", + "intoptions"); + } + + super.appendItems(artifact, creator, name, context, select); + } + + + @Override + protected Element[] createItems( + ElementCreator creator, + Artifact artifact, + String name, + CallContext context + ) { + logger.debug("createItems()"); + + if (name != null && name.equals(DATA_MODE)) { + return createModeItem(creator, artifact, name, context); + } + else if (name != null && name.equals(DATA_VALUES)) { + return createValuesItem(creator, artifact, name, context); + } + + logger.warn("Tried to create item for invalid data: " + name); + + return new Element[0]; + } + + + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + CallMeta meta = cc.getMeta(); + + if (name.equals(DATA_MODE)) { + if (value.equals(String.valueOf(DATA_MODE_W))) { + return Resources.getMsg(meta, I18N_MODE_W, I18N_MODE_W); + } + else { + return Resources.getMsg(meta, I18N_MODE_Q, I18N_MODE_Q); + } + } + else { + return value; + } + } + + + protected Element[] createModeItem( + ElementCreator creator, + Artifact artifact, + String name, + CallContext context + ) { + logger.debug("createModeItem()"); + + CallMeta meta = context.getMeta(); + + Element modeW = createItem( + creator, + new String[] { + Resources.getMsg(meta, I18N_MODE_W, I18N_MODE_W), + String.valueOf(DATA_MODE_W) } ); + + Element modeQ = createItem( + creator, + new String[] { + Resources.getMsg(meta, I18N_MODE_Q, I18N_MODE_Q), + String.valueOf(DATA_MODE_Q) } ); + + return new Element[] { modeW, modeQ }; + } + + + protected Element[] createValuesItem( + ElementCreator creator, + Artifact artifact, + String name, + CallContext context + ) { + logger.debug("createValuesItem()"); + + Element valuesW = createItem( + creator, new String[] { "ws", "" } ); + + Element valuesQ = createItem( + creator, new String[] { "qs", "" } ); + + return new Element[] { valuesW, valuesQ }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/InputDoubleState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,39 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * State to keep a double value and validate it against a range + */ +public class InputDoubleState extends MinMaxState { + + private static final Logger logger = Logger.getLogger(InputDoubleState.class); + + + @Override + protected String getUIProvider() { + return "location_panel"; + } + + + @Override + protected Object getLower(FLYSArtifact flys) { + return 0; + } + + + @Override + protected Object getUpper(FLYSArtifact flys) { + return 0; + } + + + @Override + protected String getType() { + return "double"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/IntRangeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,39 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class IntRangeState extends MinMaxState { + + private static final Logger logger = Logger.getLogger(IntRangeState.class); + + + @Override + protected String getUIProvider() { + return "timerange"; + } + + + @Override + protected Object getLower(FLYSArtifact flys) { + return 0; + } + + + @Override + protected Object getUpper(FLYSArtifact flys) { + return 0; + } + + + @Override + protected String getType() { + return "intrange"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,151 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import gnu.trove.TDoubleArrayList; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class LocationDistanceSelect +extends ComputationRangeState +{ + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(LocationDistanceSelect.class); + + /** The name of the 'mode' field. */ + public static final String MODE = "ld_mode"; + + /** The name of the 'locations' field. */ + public static final String LOCATIONS = "ld_locations"; + + + /** + * The default constructor that initializes an empty State object. + */ + public LocationDistanceSelect() { + } + + + @Override + protected String getUIProvider() { + return "location_distance_panel"; + } + + + /** Validates the range (or location). */ + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("LocationDistanceSelect.validate"); + + FLYSArtifact flys = (FLYSArtifact)artifact; + StateData mode = getData(flys, MODE); + String mValue = mode != null ? (String)mode.getValue() : null; + if (mValue != null) { + if (mValue.equals("distance")) { + return super.validate(flys); + } + else { + return validateLocations(flys); + } + } + return false; + } + + + protected boolean validateLocations(FLYSArtifact flys) + throws IllegalArgumentException + { + StateData dValues = getData(flys, LOCATIONS); + String values = dValues != null ? (String)dValues.getValue() : null; + + if (values == null || values.length() == 0) { + throw new IllegalArgumentException("error_empty_state"); + } + + double[] absMinMax = getMinMax(flys); + double[] relMinMax = getMinMaxFromString(values); + + if (relMinMax[0] < absMinMax[0] || relMinMax[0] > absMinMax[1]) { + throw new IllegalArgumentException("error_feed_from_out_of_range"); + } + + if (relMinMax[1] > absMinMax[1] || relMinMax[1] < absMinMax[0]) { + throw new IllegalArgumentException("error_feed_to_out_of_range"); + } + + return true; + } + + + /** + * Extracts the min/max values from String <i>s</i>. An + * IllegalArgumentException is thrown if there is a value that throws a + * NumberFormatException. + * + * @param s String that contains whitespace separated double values. + * + * @return a 2dmin array [min,max]. + */ + public static double[] getMinMaxFromString(String s) + throws IllegalArgumentException + { + String[] values = s.split(" "); + + double[] minmax = new double[] { + Double.MAX_VALUE, + -Double.MAX_VALUE }; + + for (String v: values) { + try { + double value = Double.valueOf(v); + + minmax[0] = minmax[0] < value ? minmax[0] : value; + minmax[1] = minmax[1] > value ? minmax[1] : value; + } + catch (NumberFormatException nfe) { + throw new IllegalArgumentException( + "error_invalid_double_value"); + } + } + + return minmax; + } + + + public static double[] getLocations(WINFOArtifact flys) { + StateData data = flys.getData(LOCATIONS); + String value = data != null ? (String) data.getValue() : null; + + if (value == null || value.length() == 0) { + logger.warn("No location data given."); + return null; + } + + String[] splitted = value.split(" "); + TDoubleArrayList values = new TDoubleArrayList(); + + for (String split: splitted) { + try { + values.add(Double.valueOf(split)); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + return values.toNativeArray(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,135 @@ +package de.intevation.flys.artifacts.states; + +import gnu.trove.TDoubleArrayList; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * This state is used to realize the input of multiple locations as string. + * + * The string should be a whitespace separated list of double values where each + * double value represents a location. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class LocationSelect extends LocationDistanceSelect { + + /** The logger used in this class.*/ + private static Logger logger = Logger.getLogger(LocationSelect.class); + + + public LocationSelect() { + } + + + /** UI Provider (which input method should the client provide to user. */ + @Override + protected String getUIProvider() { + return "location_panel"; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + double[] minmax = getMinMax(artifact); + + double minVal = Double.MIN_VALUE; + double maxVal = Double.MAX_VALUE; + + if (minmax != null) { + minVal = minmax[0]; + maxVal = minmax[1]; + } + else { + logger.warn("Could not read min/max distance values!"); + } + + if (name.equals(LOCATIONS)) { + Element min = createItem( + cr, + new String[] {"min", new Double(minVal).toString()}); + + Element max = createItem( + cr, + new String[] {"max", new Double(maxVal).toString()}); + + return new Element[] { min, max }; + } + + return null; + } + + + /** Validates data from artifact. */ + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("LocationSelect.validate"); + + FLYSArtifact flys = (FLYSArtifact) artifact; + StateData data = getData(flys, LOCATIONS); + + String locationStr = data != null + ? (String) data.getValue() + : null; + + if (locationStr == null || locationStr.length() == 0) { + logger.error("No locations given."); + throw new IllegalArgumentException("error_empty_state"); + } + + double[] minmax = getMinMax(artifact); + double[] mm = extractLocations(locationStr); + + logger.debug("Inserted min location: " + mm[0]); + logger.debug("Inserted max location: " + mm[mm.length-1]); + + return validateBounds(minmax[0], minmax[1], mm[0], mm[mm.length-1], 0d); + } + + + /** + * This method takes a string that consist of whitespace separated double + * values and returns the double values as array. + * + * @param locationStr The locations inserted in this state. + * + * @return the locations as array. + */ + protected double[] extractLocations(String locationStr) { + String[] tmp = locationStr.split(" "); + TDoubleArrayList locations = new TDoubleArrayList(); + + for (String l: tmp) { + try { + locations.add(Double.parseDouble(l)); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + locations.sort(); + + return locations.toNativeArray(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,146 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.json.JSONArray; +import org.json.JSONException; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.ManualPointsArtifact; + +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ManualPointsFacet; + +import de.intevation.flys.artifacts.resources.Resources; + +/** + * The only state for an ManualPointArtifact. + */ +public class ManualPointsSingleState +extends DefaultState +implements FacetTypes +{ + /** Developer-centric description of facet. */ + public static final String I18N_DESCRIPTION + = "facet.longitudinal_section.manualpoint"; + + /** Part of data key. */ + protected static final String DOT_DATA + = ".data"; + + /** Part of data key. */ + protected static final String DOT_LINES + = ".lines"; + + /** The logger that is used in this state. */ + private static final Logger logger = + Logger.getLogger(ManualPointsSingleState.class); + + + /** + * Add ManualPointsFacets to list of Facets. + * + * @param artifact Ignored. + * @param hash Ignored. + * @param meta CallMeta to be used for internationalization. + * @param facets List to add ManualPointsFacet to. + * + * @return null. + */ + public Object compute( + FLYSArtifact artifact, + String hash, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("ManualPointsSingleState.compute()"); + ManualPointsArtifact points = (ManualPointsArtifact) artifact; + + // Add Facet per Diagram type if data given. + for (ChartType ct: ChartType.values()) { + // Handle points. + String pointData = points.getDataAsString(ct + "." + MANUALPOINTS + + DOT_DATA); + if (pointData != null && pointData.length() != 0 + && !pointData.equals("[]")) { + String fName = ct + "." + MANUALPOINTS; + ManualPointsFacet facet = new ManualPointsFacet( + 0, + fName, + Resources.getMsg(meta, "manualpoints", "Manual Points")); + + facets.add(facet); + } + else { + //logger.debug("No points for " + ct); + } + + // Handle lines. + String linesData = points.getDataAsString(ct + "." + MANUALPOINTS + + DOT_LINES); + if (linesData != null && linesData.length() != 0 + && !linesData.equals("[]")) { + try { + JSONArray lines = new JSONArray((String) linesData); + for (int i = 0, P = lines.length(); i < P; i++) { + JSONArray array = lines.getJSONArray(i); + double y = array.getDouble(0); + String name = array.getString(1); + String fName = ct + "." + MANUALLINE; + logger.debug("have facet: " + y + " / " + name + " -> " + fName); + CrossSectionWaterLineFacet facet = new CrossSectionWaterLineFacet( + i, + fName, + name); + + facets.add(facet); + } + } + catch(JSONException e){ + logger.error("Could not decode json."); + } + + } + else { + //logger.debug("No points for " + ct); + } + } + + return null; + } + + + /** Call compute. */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return compute(artifact, hash, meta, facets); + } + + + /** Call compute. */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute(artifact, hash, context.getMeta(), facets); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,95 @@ +package de.intevation.flys.artifacts.states; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.BedHeightAccess; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.MiddleBedHeightData; +import de.intevation.flys.artifacts.model.MiddleBedHeightFacet; +import de.intevation.flys.artifacts.model.MiddleBedHeightCalculation; + + +public class MiddleBedHeight extends DefaultState implements FacetTypes { + + private static final Logger logger = Logger.getLogger(MiddleBedHeight.class); + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("MiddleBedHeight.computeAdvance"); + + List<Facet> newFacets = new ArrayList<Facet>(); + + BedHeightAccess access = new BedHeightAccess(artifact); + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult) old + : new MiddleBedHeightCalculation().calculate(access); + + if (facets == null || res == null) { + return res; + } + + MiddleBedHeightData[] data = (MiddleBedHeightData[]) res.getData(); + + logger.debug("Calculated " + data.length + " MiddleBedHeightData objects"); + + String id = getID(); + int idx = 0; + + for (MiddleBedHeightData d: data) { + if (d.getStartYear() == d.getEndYear()) { + newFacets.add(new MiddleBedHeightFacet( + idx, + MIDDLE_BED_HEIGHT_SINGLE, + d.getSoundingName(context), + ComputeType.ADVANCE, + id, + hash + )); + } + else { + newFacets.add(new MiddleBedHeightFacet( + idx, + MIDDLE_BED_HEIGHT_EPOCH, + d.getSoundingName(context), + ComputeType.ADVANCE, + id, + hash + )); + } + + idx++; + } + + Facet csv = new DataFacet( + CSV, "CSV data", ComputeType.ADVANCE, hash, id); + + // TODO ADD PDF FACET + + newFacets.add(csv); + + logger.debug("Created " + newFacets.size() + " new Facets."); + + facets.addAll(newFacets); + + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,173 @@ +package de.intevation.flys.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.ProtocolUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * State that holds minimun and maximum (for validation). + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class MinMaxState extends DefaultState { + + private static final Logger logger = Logger.getLogger(MinMaxState.class); + + @Override + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + FLYSArtifact flys = (FLYSArtifact) artifact; + + select.setAttributeNS( + ArtifactNamespaceContext.NAMESPACE_URI, + "art:type", + getType()); + + String[] defMinMax = getDefaults(artifact, name); + + Element min = ProtocolUtils.createArtNode( + creator, + "min", + new String[] { "value", "default" }, + new String[] { String.valueOf(getLower(flys)), defMinMax[0] }); + + Element max = ProtocolUtils.createArtNode( + creator, + "max", + new String[] { "value", "default" }, + new String[] { String.valueOf(getUpper(flys)), defMinMax[1] }); + + select.appendChild(min); + select.appendChild(max); + } + + + /** + * @param cc + * @param name + * @param value + * @param type + * + * @return + */ + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + if (type.indexOf("range") > 0) { + String[] minmax = extractRangeAsString(value); + + if (minmax != null) { + return minmax[0] + " - " + minmax[1]; + } + } + + return super.getLabelFor(cc, name, value, type); + } + + + /** + * Returns a string array with [min,max] from <i>rawValue</i>. + * <i>rawValue</i> should be a string like "1999;2001". + * + * @param rawValue A string with min and max separated by a ';'. + * + * @return the min and max as string array ([min,max]). + */ + protected String[] extractRangeAsString(String rawValue) { + return rawValue.split(";"); + } + + + /** + * This method returns the default values for min and max. If the static + * field DefaultState.USE_DEFAULTS is set, the minimum and maximum inserted + * by the user is returned as string. Otherwise, the absolute minimum and + * maximum are returned. + * + * @param artifact The FLYSArtifact. + * @param name The name of the parameter. + * + * @return a string array [min,max] that contains the minimum and maximum + * values for the parameter <i>name</i>. + */ + protected String[] getDefaults(Artifact artifact, String name) { + if (DefaultState.USE_DEFAULTS) { + String[] tmp = getMinMaxByParameter(artifact, name); + + return tmp != null ? tmp : getMinMaxDefaults(artifact, name); + } + else { + return getMinMaxDefaults(artifact, name); + } + } + + + /** + * Returns a string array with minimum and maximum inserted by the user as + * [min,max]. + * + * @param artifact The FLYSArtifact that stores the parameter. + * @param name The name of the parameter for raw min/max value string. + * + * @return a string array [min,max]. + */ + protected String[] getMinMaxByParameter(Artifact artifact, String name) { + FLYSArtifact flys = (FLYSArtifact) artifact; + String rawValue = flys.getDataAsString(name); + + if (rawValue == null) { + logger.debug("No value for '" + rawValue + "' existing."); + return null; + } + + logger.debug("Raw value for '" + name + "' = " + rawValue); + + return extractRangeAsString(rawValue); + } + + + /** + * Returns a string array with absolute minimum and maximum as [min,max]. + * + * @param artifact The FLYSArtifact (not used in this implementation). + * @param name The parameter name (not used in this implementation). + * + * @return a string array [min,max]. + */ + protected String[] getMinMaxDefaults(Artifact artifact, String name) { + FLYSArtifact flys = (FLYSArtifact) artifact; + + Object lower = getLower(flys); + Object upper = getUpper(flys); + + return new String[] { String.valueOf(lower), String.valueOf(upper) }; + } + + + protected abstract Object getLower(FLYSArtifact flys); + + protected abstract Object getUpper(FLYSArtifact flys); + + protected abstract String getType(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,101 @@ +package de.intevation.flys.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.model.KVP; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.utils.FLYSUtils; + + +/** + * State that holds minimun and maximum (for validation). + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class MultiIntArrayState extends DefaultState { + + private static final Logger logger = + Logger.getLogger(MultiIntArrayState.class); + + + @Override + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + try { + creator.addAttr(select, "type", "intoptions", true); + + for (KVP kvp: getOptions(artifact, name)) { + Element item = creator.create("item"); + creator.addAttr(item, "label", kvp.getValue().toString(), true); + creator.addAttr(item, "value", kvp.getKey().toString(), true); + + select.appendChild(item); + } + } + catch (IllegalArgumentException iae) { + logger.warn("Illegal argument", iae); + } + } + + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element data = creator.create("data"); + creator.addAttr(data, "name", name, true); + creator.addAttr(data, "type", type, true); + creator.addAttr(data, "label", + Resources.getMsg(cc.getMeta(), name, name), true); + + int[] values = FLYSUtils.intArrayFromString(value); + + for (int val: values) { + try { + Element item = creator.create("item"); + creator.addAttr(item, "value", String.valueOf(val), true); + creator.addAttr(item, "label", getLabelFor(cc, name, val), true); + + data.appendChild(item); + } + catch (IllegalArgumentException iae) { + logger.warn("Cannot append item: " + val, iae); + } + } + + return data; + } + + + protected abstract KVP<Integer, String>[] getOptions( + Artifact artifact, + String parameterName + ) + throws IllegalArgumentException; + + + protected abstract String getLabelFor( + CallContext cc, + String parameterName, + int value) + throws IllegalArgumentException; +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/MultiStringArrayState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,96 @@ +package de.intevation.flys.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.model.KVP; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class MultiStringArrayState extends DefaultState { + + private static final Logger logger = + Logger.getLogger(MultiStringArrayState.class); + + + @Override + protected void appendItems( + Artifact artifact, + ElementCreator creator, + String name, + CallContext context, + Element select + ) { + try { + creator.addAttr(select, "type", "options", true); + + for (KVP kvp: getOptions(artifact, name, context)) { + Element item = creator.create("item"); + creator.addAttr(item, "label", kvp.getValue().toString(), true); + creator.addAttr(item, "value", kvp.getKey().toString(), true); + + select.appendChild(item); + } + } + catch (IllegalArgumentException iae) { + logger.warn("Illegal argument", iae); + } + } + + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element data = creator.create("data"); + creator.addAttr(data, "name", name, true); + creator.addAttr(data, "type", type, true); + creator.addAttr(data, "label", + Resources.getMsg(cc.getMeta(), name, name), true); + + String[] values = value.split(";"); + + for (String val: values) { + Element item = creator.create("item"); + creator.addAttr(item, "value", val, true); + creator.addAttr(item, "label", getLabelFor(cc, name, val), true); + + data.appendChild(item); + } + + return data; + } + + + protected abstract KVP<String, String>[] getOptions( + Artifact artifact, + String parameterName, + CallContext context + ) + throws IllegalArgumentException; + + + protected abstract String getLabelFor( + CallContext cc, + String parameterName, + String value + ) + throws IllegalArgumentException; +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,41 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.data.StateData; +import de.intevation.artifacts.CallContext; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class OutliersInput extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(OutliersInput.class); + + public static final String PARAMETER_NAME = "outliers"; + + + /** + * The default constructor that initializes an empty State object. + */ + public OutliersInput() { + } + + @Override + protected String getUIProvider() { + return "outliers_input"; + } + + + @Override + protected String[] getDefaultsFor(CallContext context, StateData data) { + if (data != null && data.getName().equals(PARAMETER_NAME)) { + return new String[] {"3", "3"}; + } + + return null; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/OutputState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,43 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.FacetTypes; + + +public class OutputState extends DefaultState implements FacetTypes { + + private static final Logger logger = Logger.getLogger(OutputState.class); + + + @Override + public Element describeStatic( + Artifact artifact, + Document document, + Node root, + CallContext context, + String uuid) + { + return null; + } + + + @Override + public Element describe( + Artifact artifact, + Document document, + Node root, + CallContext context, + String uuid) + { + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/PeriodSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,21 @@ +package de.intevation.flys.artifacts.states; + +public class PeriodSelect extends DefaultState { + + public static final String UI_PROVIDER = "period_select"; + + private static final long serialVersionUID = 1L; + + /** + * The default constructor that initializes an empty State object. + */ + public PeriodSelect() { + } + + @Override + protected String getUIProvider() { + return UI_PROVIDER; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/PeriodsSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,26 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class PeriodsSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(PeriodsSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public PeriodsSelect() { + } + + @Override + protected String getUIProvider() { + return "periods_select"; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ProfileDistanceSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,13 @@ +package de.intevation.flys.artifacts.states; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ProfileDistanceSelect extends DefaultState { + + @Override + protected String getUIProvider() { + return "auto_integer"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/QSectorSingleState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,91 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.QSectorArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.QSectorFacet; + +import de.intevation.flys.artifacts.resources.Resources; + +/** + * The only state for an QSectorArtifact. + */ +public class QSectorSingleState +extends DefaultState +implements FacetTypes +{ + /** Developer-centric description of facet. */ + public static final String I18N_DESCRIPTION + = "facet.qsector"; + + /** The logger that is used in this state. */ + private static final Logger logger = + Logger.getLogger(QSectorSingleState.class); + + + /** + * Add QSectorFacets to list of Facets. + * + * @param artifact Ignored. + * @param hash Ignored. + * @param meta CallMeta to be used for internationalization. + * @param facets List to add QSectorFacet to. + * + * @return null. + */ + public Object compute( + FLYSArtifact artifact, + String hash, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("QSectorSingleState.compute()"); + QSectorArtifact points = (QSectorArtifact) artifact; + + QSectorFacet qfacet = new QSectorFacet( + 0, + QSECTOR, + Resources.getMsg(meta, "qsectors", "Q Sectors")); + + facets.add(qfacet); + + return null; + } + + + /** Call compute. */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return compute(artifact, hash, meta, facets); + } + + + /** Call compute. */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute(artifact, hash, context.getMeta(), facets); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/RangeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,106 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class RangeState extends DefaultState { + + /** The logger that is used in this class. */ + private Logger logger = Logger.getLogger(RangeState.class); + + + public RangeState() { + } + + + protected abstract String getLowerField(); + protected abstract String getUpperField(); + protected abstract String getStepField(); + protected abstract double[] getMinMax(Artifact artifact); + + + protected boolean validateBounds( + double fromValid, double toValid, + double from, double to) + throws IllegalArgumentException + { + if (from < fromValid) { + logger.error( + "Invalid 'from'. " + from + " is smaller than " + fromValid); + throw new IllegalArgumentException("error_feed_from_out_of_range"); + } + else if (to > toValid) { + logger.error( + "Invalid 'to'. " + to + " is bigger than " + toValid); + throw new IllegalArgumentException("error_feed_to_out_of_range"); + } + + return true; + } + + + /** + * Validates a given range with a given valid range. + * + * @param fromValid Valid lower value of the range. + * @param toValid Valid upper value of the range. + * @param from The lower value. + * @param to The upper value. + * @param step The step width. + * + * @return true, if everything was fine, otherwise an exception is thrown. + */ + protected boolean validateBounds( + double fromValid, double toValid, + double from, double to, double step) + throws IllegalArgumentException + { + logger.debug("RangeState.validateRange"); + + // XXX The step width is not validated at the moment! + return validateBounds(fromValid, toValid, from, to); + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData dFrom = getData(flys, getLowerField()); + StateData dTo = getData(flys, getUpperField()); + StateData dStep = getData(flys, getStepField()); + + String fromStr = dFrom != null ? (String) dFrom.getValue() : null; + String toStr = dTo != null ? (String) dTo.getValue() : null; + String stepStr = dStep != null ? (String) dStep.getValue() : null; + + if (fromStr == null || toStr == null || stepStr == null) { + throw new IllegalArgumentException("error_empty_state"); + } + + try { + double from = Double.parseDouble(fromStr); + double to = Double.parseDouble(toStr); + double step = Double.parseDouble(stepStr); + + double[] minmax = getMinMax(flys); + + return validateBounds(minmax[0], minmax[1], from, to, step); + } + catch (NumberFormatException nfe) { + throw new IllegalArgumentException("error_invalid_double_value"); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,87 @@ +package de.intevation.flys.artifacts.states; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReferenceCurveFacet; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WWQQ; + +import java.util.List; + +import org.apache.log4j.Logger; + + +/** State of WINFO in which reference curves can be produced. */ +public class ReferenceCurveState +extends DefaultState +implements FacetTypes +{ + private static Logger logger = Logger.getLogger(ReferenceCurveState.class); + + + public ReferenceCurveState() { + } + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (!(artifact instanceof WINFOArtifact)) { + return null; + } + + String id = getID(); + + WINFOArtifact winfo = (WINFOArtifact)artifact; + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult)old + : winfo.getReferenceCurveData(context); + + if (facets == null) { + return res; + } + + WWQQ [] wws = (WWQQ [])res.getData(); + + for (int i = 0; i < wws.length; ++i) { + String wwsName = wws[i].getName(); + facets.add(new ReferenceCurveFacet(i, + REFERENCE_CURVE, + wwsName + )); + facets.add(new ReferenceCurveFacet(i, + REFERENCE_CURVE_NORMALIZED, + wwsName + )); + } + + if (wws.length > 0) { + logger.debug("Adding CSV and PDF data facet."); + Facet csv = new DataFacet (CSV, "CSV data", ComputeType.ADVANCE, hash, id); + Facet pdf = new DataFacet (PDF, "PDF data", ComputeType.ADVANCE, hash, id); + facets.add(csv); + facets.add(pdf); + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ReferenceGaugeState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,88 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.utils.FLYSUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ReferenceGaugeState extends DefaultState { + + private static final Logger logger = + Logger.getLogger(ReferenceGaugeState.class); + + + public static final String DATA_NAME = "reference_gauge"; + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + + River river = FLYSUtils.getRiver((FLYSArtifact) artifact); + List<Gauge> gauges = river.getGauges(); + + int num = gauges != null ? gauges.size() : 0; + + Element[] opts = new Element[num]; + + for (int i = 0; i < num; i++ ) { + Gauge g = gauges.get(i); + + String gaugeName = g.getName(); + long officialNumber = g.getOfficialNumber(); + + opts[i] = createItem( + cr, new String[] { gaugeName, String.valueOf(officialNumber) }); + } + + return opts; + } + + + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + if (name.equals(DATA_NAME)) { + try { + long number = Long.valueOf(value); + Gauge gauge = Gauge.getGaugeByOfficialNumber(number); + + if (gauge != null) { + return gauge.getName(); + } + } + catch (NumberFormatException nfe) { + // do nothing + } + } + + return super.getLabelFor(cc, name, value, type); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.artifacts.resources.Resources; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class RiverSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(RiverSelect.class); + + /** Error message that is thrown if no river was found based on a given + * name.*/ + public static final String ERROR_NO_SUCH_RIVER = + "error_feed_no_such_river"; + + /** Error message that is thrown if no river was found based on a given + * name.*/ + public static final String ERROR_NO_RIVER_SELECTED = + "error_feed_no_river_selected"; + + + /** + * The default constructor that initializes an empty State object. + */ + public RiverSelect() { + } + + + /** + * Initialize the state based on the state node in the configuration. + * + * @param config The state configuration node. + */ + public void setup(Node config) { + super.setup(config); + } + + + protected Element createData( + XMLUtils.ElementCreator cr, + Artifact artifact, + StateData data, + CallContext context) + { + Element select = ProtocolUtils.createArtNode( + cr, "select", + new String[] { "uiprovider" }, + new String[] { "select_with_map" }); + cr.addAttr(select, "name", data.getName(), true); + + Element label = ProtocolUtils.createArtNode( + cr, "label", null, null); + + Element choices = ProtocolUtils.createArtNode( + cr, "choices", null, null); + + select.appendChild(label); + + label.setTextContent(Resources.getMsg( + context.getMeta(), + getID(), + getID())); + + return select; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + List<River> rivers = RiverFactory.getRivers(); + Element[] items = new Element[rivers.size()]; + + int idx = 0; + for (River river: rivers) { + items[idx++] = createRiverItem(cr, river); + } + + return items; + } + + + /** + * This method creates a node that represents a river item. This node + * contains the label and the value that describe the river. + * + * @param cr The ElementCreator. + * @param river The river. + * + * @return the element that contains the information about the river. + */ + protected Element createRiverItem(XMLUtils.ElementCreator cr, River river) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + label.setTextContent(river.getName()); + value.setTextContent(river.getName()); + + item.appendChild(label); + item.appendChild(value); + + return item; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("RiverSelect.validate"); + + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData dRiver = getData(flys, "river"); + + if (dRiver == null || dRiver.getValue() == null) { + throw new IllegalArgumentException(ERROR_NO_RIVER_SELECTED); + } + + River river = RiverFactory.getRiver((String) dRiver.getValue()); + + if (river == null) { + throw new IllegalArgumentException(ERROR_NO_SUCH_RIVER); + } + + return true; + } + + + @Override + protected String getUIProvider() { + return "river_panel"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/SQRelation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,295 @@ +package de.intevation.flys.artifacts.states; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.StringUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.SQRelationAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.model.sq.SQCurveFacet; +import de.intevation.flys.artifacts.model.sq.SQFractionResult; +import de.intevation.flys.artifacts.model.sq.SQMeasurementFacet; +import de.intevation.flys.artifacts.model.sq.SQOutlierCurveFacet; +import de.intevation.flys.artifacts.model.sq.SQOutlierFacet; +import de.intevation.flys.artifacts.model.sq.SQOutlierMeasurementFacet; +import de.intevation.flys.artifacts.model.sq.SQOverviewFacet; +import de.intevation.flys.artifacts.model.sq.SQRelationCalculation; +import de.intevation.flys.artifacts.model.sq.SQResult; + +import de.intevation.flys.artifacts.resources.Resources; + +import java.util.List; + +import org.apache.log4j.Logger; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class SQRelation extends DefaultState implements FacetTypes { + + private static Logger log = Logger.getLogger(SQRelation.class); + + + public static final String I18N_FACET_CURVE = + "facet.sq_relation.curve"; + + public static final String I18N_FACET_MEASUREMENTS = + "facet.sq_relation.measurements"; + + public static final String I18N_FACET_OUTLIERS = + "facet.sq_relation.outliers"; + + public static final String I18N_FACET_OUTLIER_CURVE = + "facet.sq_relation.outlier.curve"; + + public static final String I18N_FACET_OUTLIER_MEASUREMENT = + "facet.sq_relation.outlier.measurement"; + + public static final int CURVE_INDEX = 0; + public static final int MEASURREMENT_INDEX = 1; + public static final int OUTLIER_INDEX = 2; + public static final int OUTLIER_CURVE_INDEX = 3; + public static final int OUTLIER_MEASUREMENT_INDEX = 4; + + public static final String [][] FACET_NAMES = { + { SQ_A_CURVE, SQ_B_CURVE, SQ_C_CURVE, + SQ_D_CURVE, SQ_E_CURVE, SQ_F_CURVE + }, + { SQ_A_MEASUREMENT, SQ_B_MEASUREMENT, SQ_C_MEASUREMENT, + SQ_D_MEASUREMENT, SQ_E_MEASUREMENT, SQ_F_MEASUREMENT + }, + { SQ_A_OUTLIER, SQ_B_OUTLIER, SQ_C_OUTLIER, + SQ_D_OUTLIER, SQ_E_OUTLIER, SQ_F_OUTLIER + }, + { SQ_A_OUTLIER_CURVE, SQ_B_OUTLIER_CURVE, SQ_C_OUTLIER_CURVE, + SQ_D_OUTLIER_CURVE, SQ_E_OUTLIER_CURVE, SQ_F_OUTLIER_CURVE + }, + { SQ_A_OUTLIER_MEASUREMENT, SQ_B_OUTLIER_MEASUREMENT, + SQ_C_OUTLIER_MEASUREMENT, SQ_D_OUTLIER_MEASUREMENT, + SQ_E_OUTLIER_MEASUREMENT, SQ_F_OUTLIER_MEASUREMENT + } + }; + + + static { + // Active/deactivate facets. + FacetActivity.Registry.getInstance().register( + "minfo", + new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String output + ) { + String name = facet.getName(); + + if (StringUtils.contains( + name, FACET_NAMES[CURVE_INDEX]) + || StringUtils.contains( + name, FACET_NAMES[OUTLIER_INDEX]) + || StringUtils.contains( + name, FACET_NAMES[MEASURREMENT_INDEX]) + ) { + // TODO: Only the last should be active. + return Boolean.TRUE; + } + + if (StringUtils.contains( + name, FACET_NAMES[OUTLIER_CURVE_INDEX]) + || StringUtils.contains( + name, FACET_NAMES[OUTLIER_MEASUREMENT_INDEX]) + ) { + return Boolean.FALSE; + } + + return null; + } + }); + } + + + public SQRelation() { + } + + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + log.debug("SQRelation.computeAdvance"); + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult)old + : new SQRelationCalculation( + new SQRelationAccess(artifact)).calculate(); + + if (facets == null) { + return res; + } + + SQResult [] sqr = (SQResult [])res.getData(); + if (sqr == null) { + return res; + } + + createFacets(context, facets, sqr, hash); + + Facet csv = new DataFacet( + CSV, "CSV data", ComputeType.ADVANCE, hash, id); + + Facet pdf = new DataFacet( + PDF, "PDF data", ComputeType.ADVANCE, hash, id); + + facets.add(csv); + facets.add(pdf); + + return res; + } + + + protected void createFacets( + CallContext context, + List<Facet> container, + SQResult[] sqr, + String hash + ) { + boolean debug = log.isDebugEnabled(); + + CallMeta meta = context.getMeta(); + String stateId = getID(); + for (int i = 0; i < 6; i++) { + container.add(new SQOverviewFacet( + i, + i, + "sq_chart_overview", + Resources.getMsg( + meta, + I18N_FACET_CURVE, + I18N_FACET_CURVE + ), + hash, + getID() + )); + } + for (int res = 0, n = sqr.length; res < n; res++) { + + for (int i = 0; i < SQResult.NUMBER_FRACTIONS; i++) { + SQFractionResult result = sqr[res].getFraction(i); + + if (result == null) { + log.warn("Fraction at index " + i + " is empty!"); + continue; + } + + container.add(new SQCurveFacet( + res, + i, + getFractionFacetname(CURVE_INDEX, i), + Resources.getMsg( + meta, + I18N_FACET_CURVE, + I18N_FACET_CURVE + ), + hash, + stateId + )); + + for (int j = 0, C = result.numIterations()-1; j < C; j++) { + + Object [] round = new Object [] { j + 1 }; + + int index = res; + index = index << 16; + index = index + j; + + if (debug) { + log.debug("new outliers facet (index=" +index+ ")"); + log.debug(" result index = " + res); + log.debug(" fraction idx = " + i); + log.debug(" iteration = " + j); + } + + container.add(new SQOutlierFacet( + index, + i, + getFractionFacetname(OUTLIER_INDEX, i), + Resources.getMsg( + meta, + I18N_FACET_OUTLIERS, + I18N_FACET_OUTLIERS, + round + ), + hash, + stateId + )); + + container.add(new SQOutlierCurveFacet( + index, + i, + getFractionFacetname(OUTLIER_CURVE_INDEX, i), + Resources.getMsg( + meta, + I18N_FACET_OUTLIER_CURVE, + I18N_FACET_OUTLIER_CURVE, + round + ), + hash, + stateId + )); + + container.add(new SQOutlierMeasurementFacet( + index, + i, + getFractionFacetname(OUTLIER_MEASUREMENT_INDEX, i), + Resources.getMsg( + meta, + I18N_FACET_OUTLIER_MEASUREMENT, + I18N_FACET_OUTLIER_MEASUREMENT, + round + ), + hash, + stateId + )); + } // for all outliers + + container.add(new SQMeasurementFacet( + res, + i, + getFractionFacetname(MEASURREMENT_INDEX, i), + Resources.getMsg( + meta, + I18N_FACET_MEASUREMENTS, + I18N_FACET_MEASUREMENTS + ), + hash, + stateId + )); + } // for all fractions + } // for all results + } + + protected static String getFractionFacetname(int type, int idx) { + if (log.isDebugEnabled()) { + log.debug("getFractionFacetname(): " + type + " | " + idx); + } + type %= FACET_NAMES.length; + return FACET_NAMES[type][idx % FACET_NAMES[type].length]; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,157 @@ +package de.intevation.flys.artifacts.states; + +import java.io.File; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.artifacts.common.utils.FileTools; + +import de.intevation.artifactdatabase.ProtocolUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.utils.FLYSUtils; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ScenarioSelect extends DefaultState { + + /** The logger that is used in this class.*/ + private static Logger logger = Logger.getLogger(ScenarioSelect.class); + + + public static final String FIELD_MODE = "scenario"; + public static final String FIELD_BARRIERS = "uesk.barriers"; + + public static final String SCENARIO_CURRENT = "scenario.current"; + public static final String SCENARIO_POTENTIEL = "scenario.potentiel"; + public static final String SCENARIO_SCENRAIO = "scenario.scenario"; + + public static final String[] SCENARIOS = { + SCENARIO_CURRENT, + SCENARIO_POTENTIEL, + SCENARIO_SCENRAIO }; + + + + @Override + protected String getUIProvider() { + return "map_digitize"; + } + + + @Override + protected void appendStaticData( + FLYSArtifact flys, + CallContext cc, + ElementCreator creator, + Element ui, + String name + ) { + if (name != null && name.equals(FIELD_BARRIERS)) { + return; + } + else { + super.appendStaticData(flys, cc, creator, ui, name); + } + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + + if (name.equals(FIELD_MODE)) { + Element[] scenarios = new Element[SCENARIOS.length]; + + int i = 0; + + for (String scenario: SCENARIOS) { + scenarios[i++] = createItem( + cr, new String[] { + Resources.getMsg(meta, scenario, scenario), + scenario + }); + } + + return scenarios; + } + else { + FLYSArtifact flys = (FLYSArtifact) artifact; + String data = flys.getDataAsString(name); + + return new Element[] { createItem( + cr, + new String[] { + Resources.getMsg(meta, name, name), + data + } + )}; + } + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } + + + + @Override + public void endOfLife(Artifact artifact, Object callContext) { + super.endOfLife(artifact, callContext); + logger.info("ScenarioSelect.endOfLife: " + artifact.identifier()); + + FLYSArtifact flys = (FLYSArtifact) artifact; + removeDirectory(flys); + } + + + /** + * Removes the directory and all its content where the required data and the + * results of WSPLGEN are stored. Should be called in endOfLife(). + */ + protected void removeDirectory(FLYSArtifact artifact) { + String shapePath = FLYSUtils.getXPathString( + FLYSUtils.XPATH_SHAPEFILE_DIR); + + File artifactDir = new File(shapePath, artifact.identifier()); + + if (artifactDir.exists()) { + logger.info("Delete directory: " + artifactDir.getAbsolutePath()); + boolean success = FileTools.deleteRecursive(artifactDir); + } + else { + logger.debug("There is no directory to remove."); + } + } + + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,208 @@ +package de.intevation.flys.artifacts.states; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.model.KVP; + +import de.intevation.flys.model.BedHeightEpoch; +import de.intevation.flys.model.BedHeightSingle; +import de.intevation.flys.model.River; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.utils.FLYSUtils; + + +public class SoundingsSelect extends MultiStringArrayState { + + public static final String SOUNDINGS = "soundings"; + + public static final String PREFIX_SINGLE = "single-"; + + public static final String PREFIX_EPOCH = "epoch-"; + + + private static final Logger logger = Logger.getLogger(SoundingsSelect.class); + + + @Override + public String getUIProvider() { + return "parameter-matrix"; + } + + + @Override + protected KVP<String, String>[] getOptions( + Artifact artifact, + String parameterName, + CallContext context + ) + throws IllegalArgumentException + { + logger.debug("Get options for parameter: '" + parameterName + "'"); + + if (!testParameterName(parameterName)) { + throw new IllegalArgumentException( + "Invalid parameter for state: '" + parameterName + "'"); + } + + River river = FLYSUtils.getRiver((FLYSArtifact) artifact); + double lo = ((FLYSArtifact) artifact).getDataAsDouble("ld_from"); + double hi = ((FLYSArtifact) artifact).getDataAsDouble("ld_to"); + + double kmLo = Math.min(lo, hi); + double kmHi = Math.max(lo, hi); + + List<KVP<String, String>> kvp = new ArrayList<KVP<String, String>>(); + + appendSingles(river, kmLo, kmHi, kvp); + appendEpochs(river, kmLo, kmHi, kvp); + + return kvp.toArray(new KVP[kvp.size()]); + } + + + protected void appendSingles( + River river, + double kmLo, + double kmHi, + List<KVP<String, String>> kvp + ) { + List<BedHeightSingle> singles = + BedHeightSingle.getBedHeightSingles(river, kmLo, kmHi); + + if (singles != null) { + int size = singles.size(); + + logger.debug("Found " + size + " singles."); + + for (int i = 0; i < size; i++) { + BedHeightSingle s = singles.get(i); + + String id = PREFIX_SINGLE + s.getId(); + String value = s.getDescription(); + + kvp.add(new KVP(id, value)); + } + } + } + + + protected void appendEpochs( + River river, + double kmLo, + double kmHi, + List<KVP<String, String>> kvp + ) { + List<BedHeightEpoch> epochs = + BedHeightEpoch.getBedHeightEpochs(river, kmLo, kmHi); + + if (epochs != null) { + int size = epochs.size(); + + logger.debug("Found " + size + " epochs."); + + for (int i = 0; i < size; i++) { + BedHeightEpoch e = epochs.get(i); + + String id = PREFIX_EPOCH + e.getId(); + String value = e.getDescription(); + + kvp.add(new KVP(id, value)); + } + } + } + + + @Override + protected String getLabelFor( + CallContext cc, + String parameterName, + String value + ) throws IllegalArgumentException + { + if (!testParameterName(parameterName)) { + throw new IllegalArgumentException( + "Invalid parameter for state: '" + parameterName + "'"); + } + + if (value.indexOf(PREFIX_SINGLE) >= 0) { + return getLabelForSingle(cc, value); + } + else if (value.indexOf(PREFIX_EPOCH) >= 0) { + return getLabelForEpoch(cc, value); + } + + return value; + } + + + protected String getLabelForSingle(CallContext cc, String value) { + String id = value.replace(PREFIX_SINGLE, ""); + try { + BedHeightSingle s = BedHeightSingle.getBedHeightSingleById( + Integer.parseInt(id)); + + if (s != null) { + return s.getDescription(); + } + else { + return "no value for '" + id + "'"; + } + } + catch (NumberFormatException nfe) { + logger.warn("Could not parse id from string '" + id + "'", nfe); + } + + return "n.A."; + } + + + protected String getLabelForEpoch(CallContext cc, String value) { + String id = value.replace(PREFIX_EPOCH, ""); + try { + BedHeightEpoch e = BedHeightEpoch.getBedHeightEpochById( + Integer.parseInt(id)); + + if (e != null) { + return e.getDescription(); + } + else { + return "no value for '" + id + "'"; + } + } + catch (NumberFormatException nfe) { + logger.warn("Could not parse id from string '" + id + "'", nfe); + } + + return "n.A."; + } + + + /** + * This method might be used to test, if a parameter name is handled by this + * state. + * + * @param parameterName The name of a parameter. + * + * @return true, if parameterName is one of <i>MAIN_CHANNEL</i> or + * <i>TOTAL_CHANNEL</i>. Otherwise false. + */ + protected boolean testParameterName(String parameterName) { + if (parameterName == null || parameterName.length() == 0) { + return false; + } + else if (parameterName.equals(SOUNDINGS)) { + return true; + } + else { + return false; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StateFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,122 @@ +package de.intevation.flys.artifacts.states; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifactdatabase.data.DefaultStateData; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.common.utils.XMLUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class StateFactory { + + /** The logger used in this class */ + private static Logger logger = Logger.getLogger(StateFactory.class); + + /** The XPath to the classname of the state */ + public static final String XPATH_STATE = "@state"; + + /** The XPath to the data items of the state relative to the state node. */ + public static final String XPATH_DATA = "data"; + + /** The XPath to the data name relative to the data node.*/ + public static final String XPATH_DATA_NAME = "@name"; + + /** The XPath to the data type relative to the data node.*/ + public static final String XPATH_DATA_TYPE = "@type"; + + /** The XPath to the data description relative to the data node.*/ + public static final String XPATH_DATA_DESCRIPTION = "@description"; + + + /** + * Creates a new State based on the configured class provided by + * <code>stateConf</code>. + * + * @param stateConf The configuration of the state. + * + * @return a State. + */ + public static State createState(Node stateConf) { + String clazz = (String) XMLUtils.xpath( + stateConf, XPATH_STATE, XPathConstants.STRING); + + State state = null; + + try { + logger.debug("Create a new State for class: " + clazz); + state = (State) Class.forName(clazz).newInstance(); + state.setup(stateConf); + + initializeStateData(state, stateConf); + } + catch (InstantiationException ie) { + logger.error(ie, ie); + } + catch (IllegalAccessException iae) { + logger.error(iae, iae); + } + catch (ClassNotFoundException cnfe) { + logger.error(cnfe, cnfe); + } + + return state; + } + + + /** + * This method extracts the configured input data of a state and adds new + * StateData objects to the State. + * + * @param state The state. + * @param stateConf The state configuration node. + */ + protected static void initializeStateData(State state, Node stateConf) { + NodeList dataList = (NodeList) XMLUtils.xpath( + stateConf, XPATH_DATA, XPathConstants.NODESET); + + if (dataList == null || dataList.getLength() == 0) { + logger.debug("The state has no input data configured."); + + return; + } + + int items = dataList.getLength(); + + logger.debug("The state has " + items + " data items configured."); + + for (int i = 0; i < items; i++) { + Node data = dataList.item(i); + + String name = (String) XMLUtils.xpath( + data, XPATH_DATA_NAME, XPathConstants.STRING); + String type = (String) XMLUtils.xpath( + data, XPATH_DATA_TYPE, XPathConstants.STRING); + String desc = (String) XMLUtils.xpath( + data, XPATH_DATA_DESCRIPTION, XPathConstants.STRING); + + if (name == null || name.length() == 0) { + logger.warn("No name for data item at pos " + i + " found."); + continue; + } + + if (type == null || type.length() == 0) { + logger.warn("No type for data item at pos " + i + " found."); + logger.warn("Default type 'string' used."); + type = "string"; + } + + logger.debug("add StateData '" + name + "' (type '" + type + "')"); + state.addData(name, new DefaultStateData(name, desc, type)); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,110 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.HYKArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.HYKFacet; +import de.intevation.flys.artifacts.model.HYKFactory; + +/** + * Only state of a HYKArtifact. + */ +public class StaticHYKState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + transient private static final Logger logger = Logger.getLogger(StaticHYKState.class); + + + /** + * From this state can not be continued. + */ + @Override + protected String getUIProvider() { + return "noinput"; + } + + + /** + * Compute, create Facets, do the same stuff as all the other states do. + */ + protected Object compute( + HYKArtifact hyk, + CallMeta metaLocale, + String hash, + List<Facet> facets, + Object old + ) { + logger.debug("StaticHYKState.compute"); + String id = getID(); + + // Prepare comparison against cached result. + List<HYKFactory.Zone> resZones = old instanceof List + ? (List<HYKFactory.Zone>)old + : null; + + // TODO Compare against cached object. + + // Get Zones from HYKFactory + List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>) + HYKFactory.getHYKs(hyk.getHykId(), hyk.getKm()); + + if (facets == null) { + logger.debug("StaticHYKState.compute no facets"); + return zones; + } + + // Spawn Facets. + Facet facet = new HYKFacet(0, HYKFactory.getHykName(hyk.getHykId())); + facets.add(facet); + + return zones; + } + + + /** + * Get data, create the facets. + * + * @param context Ignored. + */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((HYKArtifact) artifact, context.getMeta(), + hash, facets, old); + } + + + /** + * Create the facets. + * @param context Ignored. + */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return compute((HYKArtifact) artifact, meta, hash, facets, + null); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,111 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.DefaultOutput; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +/** + * Yet, a non-abstract DefaultState. + */ +public class StaticState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static final Logger logger = Logger.getLogger(StaticState.class); + + + /** + * Trivial constructor, sets id and description. + * @param id String used for both id and description. + */ + public StaticState(String id) { + this(id, id); + } + + + public StaticState(String id, String description) { + super(); + setID(id); + setDescription(description); + } + + public void addDefaultChartOutput(String nameDesc, List<Facet> facets) { + DefaultOutput output = new DefaultOutput(nameDesc, + nameDesc, "image/png", facets, "chart"); + getOutputs().add(output); + } + + public static void addDefaultChartOutput( + DefaultState state, + String nameDesc, + List<Facet> facets + ) { + DefaultOutput output = new DefaultOutput(nameDesc, + nameDesc, "image/png", facets, "chart"); + state.getOutputs().add(output); + } + + + /** + * Do nothing (override to include your logic). + * @param facets List of facets (to add to). + */ + public Object staticCompute(List<Facet> facets, FLYSArtifact artifact) { + return staticCompute(facets); + } + + public Object staticCompute(List<Facet> facets) { + return null; + } + + + /** Call staticCompute to allow easy adjustments. */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return staticCompute(facets, artifact); + } + + + /** Call staticCompute to allow easy adjustments. */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return staticCompute(facets, artifact); + } + + + /** Call staticCompute to allow easy adjustments. */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return staticCompute(facets, artifact); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticWQKmsState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,136 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.StaticWQKmsArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WQKmsFacet; + +/** + * Only state of WQKmsArtifact. + */ +public class StaticWQKmsState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(StaticWQKmsState.class); + + + /** + * From this state can not be continued. + */ + @Override + protected String getUIProvider() { + return "noinput"; + } + + + /** + * Compute, create Facets, do the same stuff as all the other states do. + */ + protected Object compute( + StaticWQKmsArtifact winfo, + CallMeta metaLocale, + String hash, + List<Facet> facets, + Object old + ) { + String id = getID(); + + WQKms res = old instanceof WQKms + ? (WQKms)old + : winfo.getWQKms(); + + WQKms wqkms = res; + + if (facets == null) { + return res; + } + + /* + * TODO: re-enable HEIGHTMARKS_POINTS-thing + + String name; + if (parts[0].equals(HEIGHTMARKS_POINTS)) { + name = HEIGHTMARKS_POINTS; + } + else { + name = STATIC_WQKMS; + } + */ + + String wkmsName = wqkms.getName(); + Facet qfacet = new WQKmsFacet( + STATIC_WQKMS_Q, + wkmsName + // TODO re-enable translations. + /* + Resources.getMsg( + metaLocale, + wkmsName, + wkmsName)*/); + facets.add(qfacet); + + wkmsName = "W (" + wkmsName + ")"; + + Facet wfacet = new WQKmsFacet( + STATIC_WQKMS_W, + wkmsName + /* + // TODO re-enable translations. + Resources.getMsg( + metaLocale, + wkmsName, + wkmsName)*/); + facets.add(wfacet); + + return res; + } + + + /** + * Get data, create the facets. + * + * @param context Ignored. + */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((StaticWQKmsArtifact) artifact, context.getMeta(), + hash, facets, old); + } + + + /** + * Create the facets. + * @param context Ignored. + */ + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return compute((StaticWQKmsArtifact) artifact, meta, hash, facets, + null); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,191 @@ +package de.intevation.flys.artifacts.states; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.Artifact; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.ChartArtifact; + +import de.intevation.flys.artifacts.math.WKmsOperation; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.DifferenceCurveFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.StringUtil; + + +public class WDifferencesState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(WDifferencesState.class); + + + public WDifferencesState() { + } + + + /** Specify to display nothing (this is kind of a "final" state). */ + @Override + protected String getUIProvider() { + return "noinput"; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData data = flys.getData("diffids"); + + if (data == null) { + throw new IllegalArgumentException("diffids is empty"); + } + + // TODO: Also validate format. + + return true; + } + + + /** + * Access the data (wkms). + */ + protected WKms getWKms(String mingle, CallContext context) { + String[] def = mingle.split(";"); + String uuid = def[0]; + String name = def[1]; + int idx = Integer.parseInt(def[2]); + + if (name.startsWith("staticwkms")) { + StaticWKmsArtifact staticWKms = + (StaticWKmsArtifact) FLYSUtils.getArtifact( + uuid, + context); + logger.debug("WDifferencesState obtain data from StaticWKms"); + WKms wkms = staticWKms.getWKms(idx); + if (wkms == null) + logger.error("No WKms from artifact."); + return wkms; + } + + WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact( + uuid, + context); + + if (flys == null) { + logger.warn("One of the artifacts (1) for diff calculation could not be loaded"); + return null; + } + else{ + WQKms[] wqkms = (WQKms[]) flys.getWaterlevelData(). + getData(); + if (wqkms == null) + logger.warn("not waterlevels in artifact"); + else if (wqkms.length < idx) + logger.warn("not enough waterlevels in artifact"); + return wqkms[idx]; + } + } + + + /** + * Return CalculationResult with Array of WKms that are difference of + * Waterlevels. Add respective facets (DifferencesCurveFacet, DataFacet). + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + WINFOArtifact winfo = (WINFOArtifact) artifact; + String id = getID(); + + // Load the Artifacts/facets that we want to subtract and display. + // Expected format is: + // [42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;0]#[1231f2-....] + String diffids = winfo.getDataAsString("diffids"); + logger.debug("WDifferencesState has: " + diffids); + String datas[] = diffids.split("#"); + + // Validate the Data-Strings. + for (String s: datas) { + if (!WaterlevelSelectState.isValueValid(winfo.getDataAsString("diffids"))) { + // TODO: escalate. + } + } + + if (datas.length < 2) { + // TODO crash with style + } + + List<WKms> wkmss = new ArrayList<WKms>(); + + for(int i = 0; i < datas.length; i+=2) { + // e.g.: + // 42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;1 + WKms minuendWKms = getWKms(StringUtil.unbracket(datas[i+0]), + context); + WKms subtrahendWKms = getWKms(StringUtil.unbracket(datas[i+1]), + context); + + String facetName = "diff ()"; + + if (minuendWKms != null && subtrahendWKms != null) { + facetName = StringUtil.wWrap(minuendWKms.getName()) + + " - " + StringUtil.wWrap(subtrahendWKms.getName()); + WKms wkms = WKmsOperation.SUBTRACTION.operate(minuendWKms, + subtrahendWKms); + wkms.setName(facetName); + wkmss.add(wkms); + logger.debug("WKMSSubtraction happened"); + } + if (facets != null) { + facets.add(new DifferenceCurveFacet(i/2, W_DIFFERENCES, facetName, + ComputeType.ADVANCE, id, hash)); + } + } + + if (facets != null) { + facets.add(new DataFacet(CSV, "CSV data")); + facets.add(new DataFacet(PDF, "PDF data")); + logger.debug("Adding facets in WDifferencesState."); + } + else { + logger.debug("Not adding facets in WDifferencesState."); + } + + // TODO Evaluate whether null is okay as reports. + WKms[] diffs = wkmss.toArray(new WKms[wkmss.size()]); + CalculationResult result = new CalculationResult(diffs, null); + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,156 @@ +package de.intevation.flys.artifacts.states; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.Config; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.map.WMSLayerFacet; +import de.intevation.flys.artifacts.resources.Resources; + + +public class WMSBackgroundState extends OutputState { + + public static final String I18N_DESCRIPTION = "floodmap.wmsbackground"; + + public static final String XPATH_SRID = + "/artifact-database/floodmap/river[@name=$name]/srid/@value"; + + public static final String XPATH_WMS_URL = + "/artifact-database/floodmap/river[@name=$name]/background-wms/@url"; + + public static final String XPATH_WMS_LAYER = + "/artifact-database/floodmap/river[@name=$name]/background-wms/@layers"; + + + protected String url; + protected String layer; + protected String srid; + + protected Document cfg; + + protected Map<String, String> variables; + + + private static final Logger logger = Logger.getLogger(WMSBackgroundState.class); + + + @Override + public void setup(Node config) { + super.setup(config); + + logger.debug("WMSBackgroundState.setup()"); + } + + + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + logger.debug("WMSBackgroundState.computeInit()"); + + initVariables(artifact); + + if (url == null || layer == null) { + // XXX I don't remember why 'srid', 'url' and 'layer' are member + // variables. I think the reason was buffering those values. + srid = getSrid(); + url = getUrl(); + layer = getLayer(); + } + + if (url == null || layer == null) { + logger.warn("No background layers currently configured:"); + logger.warn("... add config for WMS url: " + XPATH_WMS_URL); + logger.warn("... add config for WMS layer: " + XPATH_WMS_LAYER); + return null; + } + + WMSLayerFacet facet = new WMSLayerFacet( + 0, + getFacetType(), + getTitle(meta), + ComputeType.INIT, + getID(), hash, + url); + + facet.addLayer(layer); + facet.setSrid(srid); + + facets.add(facet); + + return null; + } + + + protected Document getConfig() { + if (cfg == null) { + cfg = Config.getConfig(); + } + + return cfg; + } + + + protected void initVariables(FLYSArtifact artifact) { + String river = artifact.getDataAsString("river"); + + variables = new HashMap<String, String>(); + variables.put("name", river); + } + + + protected String getFacetType() { + return FLOODMAP_WMSBACKGROUND; + } + + + protected String getSrid() { + return (String) XMLUtils.xpath( + getConfig(), + XPATH_SRID, + XPathConstants.STRING, + null, + variables); + } + + + protected String getUrl() { + return (String) XMLUtils.xpath( + getConfig(), + XPATH_WMS_URL, + XPathConstants.STRING, + null, + variables); + } + + + protected String getLayer() { + return (String) XMLUtils.xpath( + getConfig(), + XPATH_WMS_LAYER, + XPathConstants.STRING, + null, + variables); + } + + + protected String getTitle(CallMeta meta) { + return Resources.getMsg(meta, I18N_DESCRIPTION, I18N_DESCRIPTION); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,468 @@ +package de.intevation.flys.artifacts.states; + +import java.util.ArrayList; +import java.util.List; +import java.util.Comparator; +import java.util.Collections; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.Range; +import de.intevation.flys.model.River; +import de.intevation.flys.model.Wst; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.RangeWithValues; +import de.intevation.flys.artifacts.model.WstFactory; +import de.intevation.flys.utils.FLYSUtils; + + +/** + * State to input W/Q data. + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQAdapted extends DefaultState { + + /** The logger used in this state.*/ + private static Logger logger = Logger.getLogger(WQAdapted.class); + + public static final String FIELD_WQ_MODE = "wq_isq"; + + public static final String FIELD_WQ_VALUES = "wq_values"; + + public static final class GaugeOrder implements Comparator<Gauge> { + private int order; + + public GaugeOrder(boolean up) { + order = up ? 1 : -1; + } + + public int compare(Gauge a, Gauge b) { + return order * a.getRange().getA().compareTo(b.getRange().getA()); + } + } // class GaugeOrder + + public static final GaugeOrder GAUGE_UP = new GaugeOrder(true); + public static final GaugeOrder GAUGE_DOWN = new GaugeOrder(false); + + /** Trivial, empty constructor. */ + public WQAdapted() { + } + + + /** + * This method creates one element for each gauge of the selected river that + * is intersected by the given kilometer range. Each element is a tuple of + * (from;to) where <i>from</i> is the lower bounds of the gauge or the lower + * kilometer range. <i>to</i> is the upper bounds of the gauge or the upper + * kilometer range. + * + * @param cr The ElementCreator. + * @param artifact The FLYS artifact. + * @param name The name of the data item. + * @param context The CallContext. + * + * @return a list of elements that consist of tuples of the intersected + * gauges of the selected river. + */ + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + logger.debug("WQAdapted.createItems"); + + if (name != null && name.equals(FIELD_WQ_MODE)) { + return createModeItems(cr, artifact, name, context); + } + else if (name != null && name.equals(FIELD_WQ_VALUES)) { + return createValueItems(cr, artifact, name, context); + } + else { + logger.warn("Unknown data object: " + name); + return null; + } + } + + + /** Creates "Q" and "W" items. */ + protected Element[] createModeItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + logger.debug("WQAdapted.createModeItems"); + + Element w = createItem(cr, new String[] { "w", "W" }); + Element q = createItem(cr, new String[] { "q", "Q" }); + + return new Element[] { w, q }; + } + + + protected Element[] createValueItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + logger.debug("WQAdapted.createValueItems"); + + FLYSArtifact flysArtifact = (FLYSArtifact) artifact; + + double[] dist = FLYSUtils.getKmRange(flysArtifact); + River river = FLYSUtils.getRiver(flysArtifact); + Wst wst = WstFactory.getWst(river); + List<Gauge> gauges = FLYSUtils.getGauges(flysArtifact); + + int num = gauges != null ? gauges.size() : 0; + + if (num == 0) { + logger.warn("Selected distance matches no gauges."); + return null; + } + + List<Element> elements = new ArrayList<Element>(); + + double rangeFrom = dist[0]; + double rangeTo = dist[1]; + + if (rangeFrom < rangeTo) { + Collections.sort(gauges, GAUGE_UP); + for (Gauge gauge: gauges) { + Range range = gauge.getRange(); + double lower = range.getA().doubleValue(); + double upper = range.getB().doubleValue(); + + // If gauge out of range, skip it. + if (upper <= rangeFrom || lower >= rangeTo) { + continue; + } + + double from = lower < rangeFrom ? rangeFrom : lower; + double to = upper > rangeTo ? rangeTo : upper; + + double[] mmQ = determineMinMaxQ(gauge, wst); + double[] mmW = gauge.determineMinMaxW(); + + elements.add(createItem( + cr, new String[] { from + ";" + to, ""}, mmQ, mmW)); + } + } + else { + Collections.sort(gauges, GAUGE_DOWN); + rangeFrom = dist[1]; + rangeTo = dist[0]; + for (Gauge gauge: gauges) { + Range range = gauge.getRange(); + double lower = range.getA().doubleValue(); + double upper = range.getB().doubleValue(); + + double from = lower < rangeFrom ? rangeFrom : lower; + double to = upper > rangeTo ? rangeTo : upper; + + // TODO probably need to continue out if oof range (see above). + + double[] mmQ = determineMinMaxQ(gauge, wst); + double[] mmW = gauge.determineMinMaxW(); + + elements.add(createItem( + cr, new String[] { to + ";" + from, ""}, mmQ, mmW)); + } + } + + Element[] els = new Element[elements.size()]; + return elements.toArray(els); + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + return createItem(cr, obj, null, null); + } + + + protected Element createItem( + XMLUtils.ElementCreator cr, + Object obj, + double[] q, + double[] w) + { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + if (q != null) { + Element qRange = createRangeElement(cr, q, "Q"); + item.appendChild(qRange); + } + + if (w != null) { + Element wRange = createRangeElement(cr, w, "W"); + item.appendChild(wRange); + } + + return item; + } + + + protected Element createRangeElement( + XMLUtils.ElementCreator cr, + double[] mm, + String type) + { + Element range = ProtocolUtils.createArtNode( + cr, "range", + new String[] {"type"}, + new String[] {type}); + + Element min = ProtocolUtils.createArtNode(cr, "min", null, null); + min.setTextContent(String.valueOf(mm[0])); + + Element max = ProtocolUtils.createArtNode(cr, "max", null, null); + max.setTextContent(String.valueOf(mm[1])); + + range.appendChild(min); + range.appendChild(max); + + return range; + } + + + /** + * Determines the min and max Q value for the given gauge. If no min and + * max values could be determined, this method will return + * [Double.MIN_VALUE, Double.MAX_VALUE]. + * + * @param gauge + * @param wst + * + * @return the min and max Q values for the given gauge. + */ + protected double[] determineMinMaxQ(Gauge gauge, Wst wst) { + logger.debug("WQAdapted.determineMinMaxQ"); + + double[] minmaxQ = gauge != null + ? wst.determineMinMaxQ(gauge.getRange()) + : null; + + double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE; + double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE; + + return new double[] { minQ, maxQ }; + } + + + @Override + protected String getUIProvider() { + return "wq_panel_adapted"; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQAdapted.validate"); + + FLYSArtifact flys = (FLYSArtifact) artifact; + StateData data = getData(flys, FIELD_WQ_MODE); + + String mode = data != null ? (String) data.getValue() : null; + boolean isQ = mode != null + ? Boolean.valueOf(mode) + : false; + + if (!isQ) { + return validateW(artifact); + } + else if (isQ) { + return validateQ(artifact); + } + else { + throw new IllegalArgumentException("error_feed_no_wq_mode_selected"); + } + } + + + protected boolean validateW(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQAdapted.validateW"); + FLYSArtifact flys = (FLYSArtifact) artifact; + + RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values")); + + if (rwvs == null) { + throw new IllegalArgumentException("error_missing_wq_data"); + } + + List<Gauge> gauges = FLYSUtils.getGauges((FLYSArtifact) artifact); + + for (Gauge gauge: gauges) { + Range range = gauge.getRange(); + double lower = range.getA().doubleValue(); + double upper = range.getB().doubleValue(); + + for (RangeWithValues rwv: rwvs) { + if (lower <= rwv.getStart() && upper >= rwv.getEnd()) { + compareWsWithGauge(gauge, rwv.getValues()); + } + } + } + + return true; + } + + + protected boolean validateQ(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQAdapted.validateQ"); + FLYSArtifact flys = (FLYSArtifact) artifact; + + RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values")); + + if (rwvs == null) { + throw new IllegalArgumentException("error_missing_wq_data"); + } + + List<Gauge> gauges = FLYSUtils.getGauges(flys); + River river = FLYSUtils.getRiver(flys); + Wst wst = WstFactory.getWst(river); + + for (Gauge gauge: gauges) { + Range range = gauge.getRange(); + double lower = range.getA().doubleValue(); + double upper = range.getB().doubleValue(); + + for (RangeWithValues rwv: rwvs) { + if (lower <= rwv.getStart() && upper >= rwv.getEnd()) { + compareQsWithGauge(wst, gauge, rwv.getValues()); + } + } + } + + return true; + } + + + protected boolean compareQsWithGauge(Wst wst, Gauge gauge, double[] qs) + throws IllegalArgumentException + { + double[] minmax = gauge != null + ? wst.determineMinMaxQ(gauge.getRange()) + : null; + + if (minmax == null) { + logger.warn("Could not determine min/max Q of gauge."); + return true; + } + + if (logger.isDebugEnabled()) { + logger.debug("Validate Qs with:"); + logger.debug("-- Gauge: " + gauge.getName()); + logger.debug("-- Gauge min: " + minmax[0]); + logger.debug("-- Gauge max: " + minmax[1]); + } + + for (double q: qs) { + if (q < minmax[0] || q > minmax[1]) { + throw new IllegalArgumentException( + "error_feed_q_values_invalid"); + } + } + + return true; + } + + + protected boolean compareWsWithGauge(Gauge gauge, double[] ws) + throws IllegalArgumentException + { + double[] minmax = gauge != null + ? gauge.determineMinMaxW() + : null; + + if (minmax == null) { + logger.warn("Could not determine min/max W of gauge."); + return true; + } + + if (logger.isDebugEnabled()) { + logger.debug("Validate Ws with:"); + logger.debug("-- Gauge: " + gauge.getName()); + logger.debug("-- Gauge min: " + minmax[0]); + logger.debug("-- Gauge max: " + minmax[1]); + } + + for (double w: ws) { + if (w < minmax[0] || w > minmax[1]) { + throw new IllegalArgumentException( + "error_feed_w_values_invalid"); + } + } + + return true; + } + + + protected RangeWithValues[] extractInput(StateData data) { + if (data == null) { + return null; + } + + String dataString = (String) data.getValue(); + String[] ranges = dataString.split(":"); + + List<RangeWithValues> rwv = new ArrayList<RangeWithValues>(); + + for (String range: ranges) { + String[] parts = range.split(";"); + + double lower = Double.parseDouble(parts[0]); + double upper = Double.parseDouble(parts[1]); + + String[] values = parts[2].split(","); + + int num = values.length; + double[] res = new double[num]; + + for (int i = 0; i < num; i++) { + try { + res[i] = Double.parseDouble(values[i]); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + rwv.add(new RangeWithValues(lower, upper, res)); + } + + return rwv.toArray(new RangeWithValues[rwv.size()]); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,764 @@ +package de.intevation.flys.artifacts.states; + +import java.text.NumberFormat; + +import gnu.trove.TDoubleArrayList; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; +import de.intevation.flys.model.Wst; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.model.WstFactory; +import de.intevation.flys.artifacts.model.WstValueTable; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WQSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(WQSelect.class); + + /** The default step width for Qs. */ + public static final String DEFAULT_STEP_Q = "50"; + + /** The default step width for Qs. */ + public static final String DEFAULT_STEP_W = "30"; + + /** The max number of steps for Qs and Ws. */ + public static final int MAX_STEPS = 30; + + /** The name of the 'mode' field. */ + public static final String WQ_MODE = "wq_isq"; + + /** Them name fo the 'free' field. */ + public static final String WQ_FREE = "wq_isfree"; + + /** The name of the 'selection' field. */ + public static final String WQ_SELECTION = "wq_isrange"; + + /** The name of the 'from' field. */ + public static final String WQ_FROM = "wq_from"; + + /** The name of the 'to' field. */ + public static final String WQ_TO = "wq_to"; + + /** The name of the 'step' field. */ + public static final String WQ_STEP = "wq_step"; + + /** The name of the 'single' field. */ + public static final String WQ_SINGLE = "wq_single"; + + + /** + * The default constructor that initializes an empty State object. + */ + public WQSelect() { + } + + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + if (!name.equals(WQ_SINGLE)) { + return super.createStaticData(flys, creator, cc, name, value, type); + } + + Boolean isQ = flys.getDataAsBoolean(WQ_MODE); + Boolean isFree = flys.getDataAsBoolean(WQ_FREE); + + WINFOArtifact winfo = (WINFOArtifact) flys; + + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + String label; + + if (!isQ || isFree) { + label = getLabel(winfo, cc, value); + } + else { + label = getSpecialLabel(winfo, cc, value); + } + + creator.addAttr(itemElement, "label", label, true); + + dataElement.appendChild(itemElement); + + return dataElement; + } + + + protected static String getLabel( + WINFOArtifact winfo, + CallContext cc, + String raw + ) { + String[] values = raw.split(" "); + + if (values.length < 1) { + return null; + } + + StringBuilder label = new StringBuilder(); + + NumberFormat nf = NumberFormat.getInstance( + Resources.getLocale(cc.getMeta())); + + for (String value: values) { + try { + double v = Double.parseDouble(value.trim()); + + String formatted = nf.format(v); + + if (label.length() > 0) { + label.append(';'); + } + label.append(formatted); + } + catch (NumberFormatException nfe) { + // do nothing here + } + } + + return label.toString(); + } + + + protected static String getSpecialLabel( + WINFOArtifact winfo, + CallContext cc, + String raw + ) { + String[] values = raw.split(" "); + + if (values.length < 1) { + return null; + } + + NumberFormat nf = NumberFormat.getInstance( + Resources.getLocale(cc.getMeta())); + + Gauge gauge = winfo.getGauge(); + + boolean debug = logger.isDebugEnabled(); + + StringBuilder label = new StringBuilder(); + + for (String value: values) { + try { + double v = Double.parseDouble(value.trim()); + + String tmp = nf.format(v); + String mv = FLYSUtils.getNamedMainValue(gauge, v); + + if (mv != null && mv.length() > 0) { + tmp = mv + ": " + tmp; + if (debug) { + logger.debug("Add main value: '" + mv + "'"); + } + } + if (label.length() > 0) { + label.append(';'); + } + label.append(tmp); + } + catch (NumberFormatException nfe) { + // do nothing here + } + } + + return label.toString(); + } + + + @Override + protected Element createData( + XMLUtils.ElementCreator cr, + Artifact artifact, + StateData data, + CallContext context) + { + Element select = ProtocolUtils.createArtNode( + cr, "select", null, null); + + cr.addAttr(select, "name", data.getName(), true); + + Element label = ProtocolUtils.createArtNode( + cr, "label", null, null); + + Element choices = ProtocolUtils.createArtNode( + cr, "choices", null, null); + + label.setTextContent(Resources.getMsg( + context.getMeta(), + data.getName(), + data.getName())); + + select.appendChild(label); + + return select; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + double[] minmaxW = determineMinMaxW(artifact); + double[] minmaxWFree = determineMinMaxWFree(artifact); + double[] minmaxQ = determineMinMaxQAtGauge(artifact); + double[] minmaxQFree = determineMinMaxQ(artifact); + + if (name.equals("wq_from")) { + Element minW = createItem(cr, new String[] { + "minW", + String.valueOf(minmaxW[0])}); + + Element minQ = createItem(cr, new String[] { + "minQ", + String.valueOf(minmaxQ[0])}); + + Element minQFree = createItem(cr, new String[] { + "minQFree", + String.valueOf(minmaxQFree[0])}); + + Element minWFree = createItem(cr, new String[] { + "minWFree", + String.valueOf(minmaxWFree[0])}); + + return new Element[] { minW, minQ, minQFree, minWFree }; + } + else if (name.equals("wq_to")) { + Element maxW = createItem(cr, new String[] { + "maxW", + String.valueOf(minmaxW[1])}); + + Element maxQ = createItem(cr, new String[] { + "maxQ", + String.valueOf(minmaxQ[1])}); + + Element maxQFree = createItem(cr, new String[] { + "maxQFree", + String.valueOf(minmaxQFree[1])}); + + Element maxWFree = createItem(cr, new String[] { + "maxWFree", + String.valueOf(minmaxWFree[1])}); + + return new Element[] { maxW, maxQ, maxQFree, maxWFree }; + } + else { + Element stepW = createItem( + cr, new String[] { + "stepW", + String.valueOf(getStepsW(minmaxW[0], minmaxW[1]))}); + Element stepQ = createItem( + cr, new String[] { + "stepQ", + String.valueOf(getStepsQ(minmaxQ[0], minmaxQ[1]))}); + Element stepQFree = createItem( + cr, new String[] { + "stepQFree", + String.valueOf(getStepsQ(minmaxQFree[0], minmaxQFree[1]))}); + Element stepWFree = createItem( + cr, new String[] { + "stepWFree", + String.valueOf(getStepsW(minmaxWFree[0], minmaxWFree[1]))}); + + return new Element[] { stepW, stepQ, stepQFree, stepWFree }; + } + } + + + protected static double getStepsW(double min, double max) { + double diff = min < max ? max - min : min - max; + double step = diff / MAX_STEPS; + + if (step < 10) { + return getSteps(step, 1); + } + else if (step < 100) { + return getSteps(step, 10); + } + else if (step < 1000) { + return getSteps(step, 100); + } + else { + return step; + } + } + + + protected static double getStepsQ(double min, double max) { + double diff = min < max ? max - min : min - max; + double step = diff / MAX_STEPS; + + if (step < 10) { + return getSteps(step, 1); + } + else if (step < 100) { + return getSteps(step, 10); + } + else if (step < 1000) { + return getSteps(step, 100); + } + else { + return step; + } + } + + + protected static double getSteps(double steps, double factor) { + int fac = (int) (steps / factor); + double diff = steps - fac * factor; + + if (diff == 0) { + return steps; + } + + return factor * (fac + 1); + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } + + + @Override + protected String getUIProvider() { + return "wq_panel"; + } + + + /** + * Determines the min and max W value for the current gauge. If no min and + * max values could be determined, this method will return + * [Double.MIN_VALUE, Double.MAX_VALUE]. + * + * @param artifact The FLYSArtifact. + * + * @return the min and max W values for the current gauge. + */ + protected double[] determineMinMaxW(Artifact artifact) { + logger.debug("WQSelect.determineCurrentGauge"); + + Gauge gauge = ((WINFOArtifact) artifact).getGauge(); + double[] minmaxW = gauge != null ? gauge.determineMinMaxW() : null; + + double minW = minmaxW != null ? minmaxW[0] : Double.MIN_VALUE; + double maxW = minmaxW != null ? minmaxW[1] : Double.MAX_VALUE; + + return new double[] { minW, maxW }; + } + + + /** + * Determines the min and max W value. If no min and + * max values could be determined, this method will return + * [Double.MIN_VALUE, Double.MAX_VALUE]. + * + * @param artifact The FLYSArtifact. + * + * @return the min and max W values. + */ + protected double[] determineMinMaxWFree(Artifact artifact) { + logger.debug("WQSelect.determineMinMaxWFree"); + + WINFOArtifact winfo = (WINFOArtifact) artifact; + WstValueTable valueTable = winfo.getWstValueTable(); + + double[] minmaxW = null; + if(valueTable != null) { + double[] km = null; + if(winfo.isRange()) { + km = winfo.getFromToStep(); + // Use the start km to determine the min max values. + minmaxW = valueTable.getMinMaxW(km[0]); + } + else { + km = winfo.getKms(); + minmaxW = valueTable.getMinMaxW(km[0]); + } + } + return minmaxW != null + ? minmaxW + : new double[] { Double.MIN_VALUE, Double.MAX_VALUE }; + } + + + /** + * Determines the min and max Q value for the current gauge. If no min and + * max values could be determined, this method will return + * [Double.MIN_VALUE, Double.MAX_VALUE]. + * + * @param artifact The FLYSArtifact. + * + * @return the min and max Q values for the current gauge. + */ + protected double[] determineMinMaxQAtGauge(Artifact artifact) { + logger.debug("WQSelect.determineMinMaxQAtGauge"); + + WINFOArtifact flysArtifact = (WINFOArtifact) artifact; + + River river = FLYSUtils.getRiver(flysArtifact); + Gauge gauge = flysArtifact.getGauge(); + Wst wst = WstFactory.getWst(river); + + double[] minmaxQ = gauge != null + ? wst.determineMinMaxQ(gauge.getRange()) + : null; + + double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE; + double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE; + + return new double[] { minQ, maxQ }; + } + + + /** + * Determines the min and max Q value for the current kilometer range. If no + * min and max values could be determined, this method will return + * + * @param artifact The FLYSArtifact. + * + * @return the min and max Q values for the current kilometer range. + */ + protected double[] determineMinMaxQ(Artifact artifact) { + logger.debug("WQSelect.determineMinMaxQ"); + + WINFOArtifact winfo = (WINFOArtifact) artifact; + WstValueTable valueTable = winfo.getWstValueTable(); + + double[] minmaxQ = null; + if(valueTable != null) { + double[] km = null; + if(winfo.isRange()) { + km = winfo.getFromToStep(); + minmaxQ = valueTable.getMinMaxQ(km[0], km[1], km[2]); + } + else { + km = winfo.getKms(); + minmaxQ = valueTable.getMinMaxQ(km[0]); + for (int i = 1; i < km.length; i++) { + double[] tmp = valueTable.getMinMaxQ(km[i]); + if(tmp[0] < minmaxQ[0]) { + minmaxQ[0] = tmp[0]; + } + if(tmp[1] > minmaxQ[1]) { + minmaxQ[1] = tmp[1]; + } + } + } + } + return minmaxQ != null + ? minmaxQ + : new double[] { Double.MIN_VALUE, Double.MAX_VALUE }; + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQSelect.validate"); + + WINFOArtifact flys = (WINFOArtifact) artifact; + + StateData data = getData(flys, WQ_SELECTION); + boolean isRange = data != null + ? Boolean.valueOf((String) data.getValue()) + : false; + + + + if (!isRange) { + return validateSingle(artifact); + } + else { + return validateRange(artifact); + } + } + + + protected boolean validateBounds( + double fromValid, double toValid, + double from, double to, double step) + throws IllegalArgumentException + { + logger.debug("RangeState.validateRange"); + + if (from < fromValid) { + logger.error( + "Invalid 'from'. " + from + " is smaller than " + fromValid); + throw new IllegalArgumentException("error_feed_from_out_of_range"); + } + else if (to > toValid) { + logger.error( + "Invalid 'to'. " + to + " is bigger than " + toValid); + throw new IllegalArgumentException("error_feed_to_out_of_range"); + } + + return true; + } + + + protected boolean validateSingle(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateSingle"); + + WINFOArtifact flys = (WINFOArtifact) artifact; + StateData data = getData(flys, WQ_SINGLE); + + String tmp = data != null ? (String) data.getValue() : null; + + if (tmp == null || tmp.length() == 0) { + throw new IllegalArgumentException("error_empty_state"); + } + + String[] strValues = tmp.split(" "); + TDoubleArrayList all = new TDoubleArrayList(); + + for (String strValue: strValues) { + try { + all.add(Double.parseDouble(strValue)); + } + catch (NumberFormatException nfe) { + logger.warn(nfe, nfe); + } + } + + all.sort(); + + FLYSUtils.WQ_MODE mode = FLYSUtils.getWQMode(flys); + + logger.debug("WQ Mode: " + mode); + + double[] minmax = null; + + if (mode == FLYSUtils.WQ_MODE.WGAUGE) { + minmax = determineMinMaxW(artifact); + } + else if (mode == FLYSUtils.WQ_MODE.QGAUGE) { + minmax = determineMinMaxQAtGauge(artifact); + } + else if (mode == FLYSUtils.WQ_MODE.QFREE) { + minmax = determineMinMaxQ(artifact); + } + else { + minmax = determineMinMaxWFree(artifact); + } + + double min = all.get(0); + double max = all.get(all.size()-1); + + logger.debug("Inserted min value = " + min); + logger.debug("Inserted max value = " + max); + + return validateBounds(minmax[0], minmax[1], min, max, 0d); + } + + + protected boolean validateRange(Artifact artifact) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateRange"); + + WINFOArtifact flys = (WINFOArtifact) artifact; + FLYSUtils.WQ_MODE mode = FLYSUtils.getWQMode(flys); + + if (mode == null) { + throw new IllegalArgumentException("error_feed_invalid_wq_mode"); + } + + StateData dFrom = flys.getData(WQ_FROM); + StateData dTo = flys.getData(WQ_TO); + StateData dStep = flys.getData(WQ_STEP); + + String fromStr = dFrom != null ? (String) dFrom.getValue() : null; + String toStr = dTo != null ? (String) dTo.getValue() : null; + String stepStr = dStep != null ? (String) dStep.getValue() : null; + + if (fromStr == null || toStr == null || stepStr == null) { + throw new IllegalArgumentException("error_empty_state"); + } + + try { + double from = Double.parseDouble(fromStr); + double to = Double.parseDouble(toStr); + double step = Double.parseDouble(stepStr); + + if (mode == FLYSUtils.WQ_MODE.WGAUGE) { + return validateGaugeW(artifact, from, to, step); + } + else if (mode == FLYSUtils.WQ_MODE.QGAUGE) { + return validateGaugeQ(artifact, from, to, step); + } + else if (mode == FLYSUtils.WQ_MODE.QFREE) { + return validateFreeQ(artifact, from, to, step); + } + else if (mode == FLYSUtils.WQ_MODE.WFREE) { + return validateFreeW(artifact, from, to, step); + } + else { + throw new IllegalArgumentException( + "error_feed_invalid_wq_mode"); + } + } + catch (NumberFormatException nfe) { + throw new IllegalArgumentException("error_feed_number_format"); + } + } + + + /** + * Validates the inserted W values. + * + * @param artifact The owner artifact. + * @param from The lower value of the W range. + * @param to The upper value of the W range. + * @param step The step width. + * + * @return true, if everything was fine, otherwise an exception is thrown. + */ + protected boolean validateGaugeW( + Artifact artifact, + double from, + double to, + double step) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateGaugeW"); + + double[] minmaxW = determineMinMaxW(artifact); + + return validateBounds(minmaxW[0], minmaxW[1], from, to, step); + } + + + /** + * Validates the inserted Q values based on the Q range for the current + * gauge. + * + * @param artifact The owner artifact. + * @param from The lower value of the Q range. + * @param to The upper value of the Q range. + * @param step The step width. + * + * @return true, if everything was fine, otherwise an exception is thrown. + */ + protected boolean validateGaugeQ( + Artifact artifact, + double from, + double to, + double step) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateGaugeQ"); + + double[] minmaxQ = determineMinMaxQAtGauge(artifact); + + return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step); + } + + + /** + * Validates the inserted Q values based on the Q range for the current + * kilometer range. + * + * @param artifact The owner artifact. + * @param from The lower value of the Q range. + * @param to The upper value of the Q range. + * @param step The step width. + * + * @return true, if everything was fine, otherwise an exception is thrown. + */ + protected boolean validateFreeQ( + Artifact artifact, + double from, + double to, + double step) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateFreeQ"); + + double[] minmaxQ = determineMinMaxQ(artifact); + + return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step); + } + + + /** + * Validates the inserted W values based on the W range for the current + * kilometer range. + * + * @param artifact The owner artifact. + * @param from The lower value of the W range. + * @param to The upper value of the W range. + * @param step The step width. + * + * @return true, if everything was fine, otherwise an exception is thrown. + */ + protected boolean validateFreeW( + Artifact artifact, + double from, + double to, + double step) + throws IllegalArgumentException + { + logger.debug("WQSelect.validateFreeW"); + + double[] minmaxW = determineMinMaxWFree(artifact); + + return validateBounds(minmaxW[0], minmaxW[1], from, to, step); + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelGroundDifferences.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,126 @@ +package de.intevation.flys.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.ProtocolUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WaterlevelGroundDifferences extends RangeState { + + public static final String LOWER_FIELD = "diff_from"; + public static final String UPPER_FIELD = "diff_to"; + public static final String DIFF_FIELD = "diff_diff"; + + public static final double DEFAULT_STEP = 0d; + + + private static Logger logger = + Logger.getLogger(WaterlevelGroundDifferences.class); + + + + @Override + protected String getLowerField() { + return LOWER_FIELD; + } + + + @Override + protected String getUpperField() { + return UPPER_FIELD; + } + + + @Override + protected String getStepField() { + return DIFF_FIELD; + } + + + @Override + protected double[] getMinMax(Artifact artifact) { + return new double[] { -Double.MAX_VALUE, Double.MAX_VALUE }; + } + + + @Override + protected String getUIProvider() { + return "waterlevel_ground_panel"; + } + + + protected double getDefaultStep() { + return DEFAULT_STEP; + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + double[] minmax = getMinMax(artifact); + + double minVal = Double.MIN_VALUE; + double maxVal = Double.MAX_VALUE; + + if (minmax != null) { + minVal = minmax[0]; + maxVal = minmax[1]; + } + else { + logger.warn("Could not read min/max distance values!"); + } + + if (name.equals(LOWER_FIELD)) { + Element min = createItem( + cr, + new String[] {"min", new Double(minVal).toString()}); + + return new Element[] { min }; + } + else if (name.equals(UPPER_FIELD)) { + Element max = createItem( + cr, + new String[] {"max", new Double(maxVal).toString()}); + + return new Element[] { max }; + } + else { + Element step = createItem( + cr, + new String[] {"step", String.valueOf(getDefaultStep())}); + return new Element[] { step }; + } + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,145 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WaterlevelFacet; +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.CalculationResult; + + +public class WaterlevelInfoState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(WaterlevelInfoState.class); + + + @Override + protected String getUIProvider() { + return "noinput"; + } + + + @Override + public Object computeInit( + FLYSArtifact artifact, + String hash, + Object context, + CallMeta meta, + List<Facet> facets + ) { + return compute((WINFOArtifact) artifact, hash, facets, null); + } + + + protected Object compute( + WINFOArtifact winfo, + String hash, + List<Facet> facets, + Object old + ) { + logger.debug("WaterlevelInfoState.compute"); + String id = getID(); + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult)old + : winfo.getWaterlevelData(); + + if (facets == null) { + return res; + } + + WQKms [] wqkms = (WQKms [])res.getData(); + + for (int i = 0; i < wqkms.length; i++) { + String nameW = null; + String nameQ = null; + + if (winfo.isQ()) { + nameQ = wqkms[i].getName(); + nameW = "W(" + nameQ + ")"; + } + else { + nameW = wqkms[i].getName(); + nameQ = "Q(" + nameQ + ")"; + } + + logger.debug("WaterlevelInfoState Create facet: " + nameW); + logger.debug("WaterlevelInfoState Create facet: " + nameQ); + + Facet w = new WaterlevelFacet( + i, LONGITUDINAL_W, nameW, ComputeType.ADVANCE, id, hash); + Facet q = new WaterlevelFacet( + i, LONGITUDINAL_Q, nameQ, ComputeType.ADVANCE, id, hash); + + facets.add(w); + facets.add(q); + } + + if (wqkms.length > 0) { + Facet wst = new DataFacet( + WST, "WST data", ComputeType.ADVANCE, hash, id); + Facet csv = new DataFacet( + CSV, "CSV data", ComputeType.ADVANCE, hash, id); + + facets.add(wst); + facets.add(csv); + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + // TODO Adjust to WaterlevelState - implementation. + facets.add(new CrossSectionWaterLineFacet(0, "Q=" + winfo.getDataAsString("wq_single"))); + + // Assume to be in wq_single mode. + return res; + } + + + /** + * @param context Ignored. + */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((WINFOArtifact) artifact, hash, facets, old); + } + + + /** + * @param context Ignored. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + return compute((WINFOArtifact) artifact, hash, facets, old); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.artifacts.states; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.ProtocolUtils; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.StringUtil; + +/** + * State in which the user selects 1 to n pairs of Waterlevels and alikes. + */ +public class WaterlevelPairSelectState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger( + WaterlevelPairSelectState.class); + + + /** Trivial constructor. */ + public WaterlevelPairSelectState() { + } + + + /** Specify to display a datacage_twin_panel. */ + @Override + protected String getUIProvider() { + return "datacage_twin_panel"; + } + + + /** + * Overridden to do nothing. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + //Get data and do stuff, do not calculate + return ""; + } + + + /** + * Create elements for document (prepopulated with data, if any). + * @param artifact FLYSArtifact to get data from. + * @param name DataName, expceted to be "diffids". + */ + @Override + protected Element[] createItems( + ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + logger.debug("createItems: " + name); + if (name.equals("diffids")) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + FLYSArtifact flys = (FLYSArtifact) artifact; + String s = flys.getDataAsString("diffids"); + value.setTextContent(s); + item.appendChild(label); + item.appendChild(value); + return new Element[] { item }; + } + return new Element[] {}; + } + + + /** + * Creats the data element used for the static part of DESCRIBE document. + */ + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + String[] labels = getLabels(cc, value); + Object[] obj = new Object[] { labels[0] }; + + // TODO own i18n + String attrValue = Resources.getMsg( + cc.getMeta(), "wsp.selected.string", "wsp.selected.string", obj); + //I18N_STATIC_KEY, I18N_STATIC_KEY, obj); + + creator.addAttr(itemElement, "label", attrValue, true); + dataElement.appendChild(itemElement); + + return dataElement; + } + + + /** + * Get name to display for selected watelerlevels (for example "Q=123") + * from the CalculationResult. + */ + public static String[] getLabels(CallContext cc, String value) { + String[] recommendations = value.split("#"); + String displayString = ""; + + // Walk over all selected recommendations and create label + // like "W (Q=1) - W (Q=2)". + for (int i = 0; i < recommendations.length; i+=2) { + String[] minuendParts = StringUtil + .unbracket(recommendations[i+0]) + .split(";"); + if(minuendParts.length >= 4) { + displayString += "(" + minuendParts[3]; + } + else { + displayString += "([error]"; + } + + displayString += " - "; + + String[] subtrahendParts = StringUtil + .unbracket(recommendations[i+1]) + .split(";"); + if(subtrahendParts.length >= 4) { + displayString += subtrahendParts[3] + ") "; + } + else { + displayString += "[error])"; + } + } + + return new String[] { displayString }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,184 @@ +package de.intevation.flys.artifacts.states; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.data.DefaultStateData; +import de.intevation.artifactdatabase.data.StateData; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.StringUtil; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WaterlevelSelectState extends DefaultState { + + private static final Logger logger = + Logger.getLogger(WaterlevelSelectState.class); + + public static final String SPLIT_CHAR = ";"; + + public static final String WINFO_WSP_STATE_ID = "state.winfo.waterlevel"; + + public static final String I18N_STATIC_KEY = "wsp.selected.string"; + + + @Override + protected String getUIProvider() { + return "wsp_datacage_panel"; + } + + + /** + * @param flys ignored + * @param cc ignrored + */ + @Override + public StateData transform( + FLYSArtifact flys, + CallContext cc, + StateData stateData, + String name, + String val + ) { + if (!isValueValid(val)) { + logger.error("The given input string is not valid: '" + val + "'"); + return null; + } + + return new DefaultStateData(name, null, null, StringUtil.unbracket(val)); + } + + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + FLYSArtifact flys = (FLYSArtifact) artifact; + + StateData data = flys.getData("wsp"); + + if (data == null) { + throw new IllegalArgumentException("WSP is empty"); + } + + return true; + } + + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + String[] labels = getLabels(cc, value); + Object[] obj = new Object[] { labels[0] }; + + String attrValue = Resources.getMsg( + cc.getMeta(), I18N_STATIC_KEY, I18N_STATIC_KEY, obj); + + creator.addAttr(itemElement, "label", attrValue, true); + dataElement.appendChild(itemElement); + + return dataElement; + } + + + /** + * Get name to display for selected watelerlevel (for example "Q=123") + * from the CalculationResult. + */ + public static String[] getLabels(CallContext cc, String value) { + String[] parts = value.split(SPLIT_CHAR); + + FLYSArtifact artifact = FLYSUtils.getArtifact(parts[0], cc); + + CalculationResult rawData = (CalculationResult) artifact.compute( + cc, + null, + WINFO_WSP_STATE_ID, + ComputeType.ADVANCE, + false); + + WQKms[] wqkms = (WQKms[]) rawData.getData(); + + int idx = -1; + try { + idx = Integer.parseInt(parts[2]); + } + catch (NumberFormatException nfe) { /* do nothing */ } + + String name = wqkms[idx].getName(); + + return new String[] { StringUtil.wWrap(name) }; + } + + + /** + * Validates the given String. A valid string for this state requires the + * format: "UUID;FACETNAME;FACETINDEX". + * + * @param value The string value requires validation. + * + * @return true, if the string applies the specified format, otherwise + * false. + */ + public static boolean isValueValid(String value) { + logger.debug("Validate string: '" + value + "'"); + + value = StringUtil.unbracket(value); + + logger.debug("Validate substring: '" + value + "'"); + + if (value == null || value.length() == 0) { + return false; + } + + String[] parts = value.split(SPLIT_CHAR); + + if (parts == null || parts.length < 3) { + return false; + } + + if (parts[0] == null || parts[0].length() == 0) { + return false; + } + + if (parts[1] == null || parts[1].length() == 0) { + return false; + } + + try { + Integer.parseInt(parts[2]); + } + catch (NumberFormatException nfe) { + logger.error("Index is not a valid integer!", nfe); + } + + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,157 @@ +package de.intevation.flys.artifacts.states; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.ChartArtifact; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WaterlevelFacet; + +import de.intevation.flys.utils.FLYSUtils; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class WaterlevelState +extends DefaultState +implements FacetTypes +{ + /** The logger that is used in this state. */ + private static Logger logger = Logger.getLogger(WaterlevelState.class); + + + /** + * From this state can only be continued trivially. + */ + @Override + protected String getUIProvider() { + return "continue"; + } + + + /** + * Compute result or returned object from cache, create facets. + * @param old Object that was cached. + */ + protected Object compute( + WINFOArtifact winfo, + CallContext cc, + String hash, + List<Facet> facets, + Object old + ) { + String id = getID(); + + CalculationResult res = old instanceof CalculationResult + ? (CalculationResult) old + : winfo.getWaterlevelData(); + + if (facets == null) { + return res; + } + + boolean debug = logger.isDebugEnabled(); + + WQKms [] wqkms = (WQKms []) res.getData(); + + for (int i = 0; i < wqkms.length; i++) { + String name = wqkms[i].getName(); + + String nameW = FLYSUtils.createWspWTitle(winfo, cc, name); + String nameQ = FLYSUtils.createWspQTitle(winfo, cc, name); + + // Hotfix for theme names. Themes with the same name cause problems + // aggregating chart legend items. + if (i > 0 && name.equals(wqkms[i - 1].getName())) { + nameW += "; Q=" + wqkms[i].get(0, new double[3])[1]; + nameQ += " = " + wqkms[i].get(0, new double[3])[1]; + } + + if (debug) { + logger.debug("Create facet: " + nameW); + logger.debug("Create facet: " + nameQ); + } + + Facet w = new WaterlevelFacet( + i, LONGITUDINAL_W, nameW, ComputeType.ADVANCE, id, hash); + Facet q = new WaterlevelFacet( + i, LONGITUDINAL_Q, nameQ, ComputeType.ADVANCE, id, hash); + + facets.add(new CrossSectionWaterLineFacet(i, nameW)); + + facets.add(w); + facets.add(q); + } + + if (wqkms.length > 0) { + Facet wst = new DataFacet( + WST, "WST data", ComputeType.ADVANCE, hash, id); + Facet csv = new DataFacet( + CSV, "CSV data", ComputeType.ADVANCE, hash, id); + Facet pdf = new DataFacet( + PDF, "PDF data", ComputeType.ADVANCE, hash, id); + + facets.add(wst); + facets.add(csv); + facets.add(pdf); + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + return res; + } + + + /** + * @param context Ignored. + */ + @Override + public Object computeFeed( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + return compute((WINFOArtifact) artifact, context, hash, facets, old); + } + + + /** + * @param context Ignored. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + if (artifact instanceof ChartArtifact) { + ChartArtifact chart = (ChartArtifact)artifact; + facets.add(new EmptyFacet()); + return null; + } + return compute((WINFOArtifact) artifact, context, hash, facets, old); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/extreme/ExtremeCompute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,65 @@ +package de.intevation.flys.artifacts.states.extreme; + +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.ExtremeAccess; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.ReportFacet; + +import de.intevation.flys.artifacts.model.extreme.ExtremeCalculation; + +import de.intevation.flys.artifacts.states.DefaultState; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class ExtremeCompute +extends DefaultState +{ + private static Logger log = Logger.getLogger(ExtremeCompute.class); + + public ExtremeCompute() { + } + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + log.debug("ExtremeCompute.computeAdvance"); + + CalculationResult res; + + ExtremeAccess access = new ExtremeAccess(artifact); + + if (old instanceof CalculationResult) { + res = (CalculationResult)old; + } + else { + ExtremeCalculation calc = new ExtremeCalculation(access); + res = calc.calculate(); + } + + if (facets == null) { + return res; + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + + // TODO: Add more facets. + + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class AnalysisPeriods extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(AnalysisPeriods.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public AnalysisPeriods() { + } + + @Override + protected String getUIProvider() { + return "fix.period_ana_panel"; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/EventSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.flys.artifacts.states.fixation; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.model.FixingsOverview; +import de.intevation.flys.artifacts.model.FixingsOverviewFactory; +import de.intevation.flys.artifacts.model.FixingsOverview.IdFilter; +import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class EventSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(EventSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public EventSelect() { + } + + @Override + protected String getUIProvider() { + return "fix.event_panel"; + } + + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + int[] array = FLYSUtils.intArrayFromString(value); + + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + String river = FLYSUtils.getRiver(flys).getName(); + + FixingsOverview overview = FixingsOverviewFactory.getOverview(river); + + for (int i = 0; i < array.length; i++) { + Element itemElement = creator.create("item"); + creator.addAttr( + itemElement, + "value", + String.valueOf(array[i]), + true); + + creator.addAttr( + itemElement, + "label", + getLabel(cc, array[i], overview), + true); + dataElement.appendChild(itemElement); + } + return dataElement; + } + + + public static String getLabel( + CallContext cc, + int value, + FixingsOverview overview + ) { + logger.debug("Create label for value: " + value); + + IdFilter filter = new IdFilter(value); + List<Fixing.Column> columns = overview.filter(null, filter); + if (!columns.isEmpty()) { + return columns.get(0).getDescription(); + } + + return ""; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,308 @@ +package de.intevation.flys.artifacts.states.fixation; + +import java.text.DateFormat; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.FixAnalysisAccess; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.fixings.FixAnalysisCalculation; +import de.intevation.flys.artifacts.model.fixings.FixAnalysisEventsFacet; +import de.intevation.flys.artifacts.model.fixings.FixAnalysisPeriodsFacet; +import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult; +import de.intevation.flys.artifacts.model.fixings.FixAvSectorFacet; +import de.intevation.flys.artifacts.model.fixings.FixDerivateFacet; +import de.intevation.flys.artifacts.model.fixings.FixDeviationFacet; +import de.intevation.flys.artifacts.model.fixings.FixLongitudinalAnalysisFacet; +import de.intevation.flys.artifacts.model.fixings.FixLongitudinalAvSectorFacet; +import de.intevation.flys.artifacts.model.fixings.FixLongitudinalDeviationFacet; +import de.intevation.flys.artifacts.model.fixings.FixLongitudinalReferenceFacet; +import de.intevation.flys.artifacts.model.fixings.FixOutlierFacet; +import de.intevation.flys.artifacts.model.fixings.FixReferenceEventsFacet; +import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.utils.IdGenerator; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixAnalysisCompute +extends DefaultState +implements FacetTypes +{ + /** The log used in this class. */ + private static Logger log = Logger.getLogger(FixAnalysisCompute.class); + + private static final String I18N_REFERENCEPERIOD = "fix.reference.period.event.short"; + + private static final String I18N_ANALYSISPERIODS = "fix.analysis.periods"; + + private static final String I18N_DERIVATIVE = "fix.derivative"; + + private static final String I18N_OUTLIER = "fix.outlier"; + + private static final String I18N_ANALYSIS = "fix.analysis.short"; + + private static final String I18N_DEVIATION = "fix.deviation"; + + private static final String I18N_REFERENCEDEVIATION = "fix.reference.deviation"; + + public static final String [] SECTOR_LABELS = { + "[0 - (MNQ+MQ)/2)", + "[(MNQ+MQ)/2 - (MQ+MHQ)/2)", + "[(MQ+MHQ)/2 - HQ5)", + "[HQ5 - \u221e)" + }; + + static { + // Active/deactivate facets. + FacetActivity.Registry.getInstance().register( + "fixanalysis", + new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String output + ) { + String name = facet.getName(); + + if (name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_DWT) + || name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_LS) + || name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_WQ) + || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_DWT) + || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_LS) + || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_WQ) + ) { + return Boolean.FALSE; + } + + return Boolean.TRUE; + } + }); + } + + /** + * The default constructor that initializes an empty State object. + */ + public FixAnalysisCompute() { + } + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + log.debug("FixAnalysisCompute.computeAdvance"); + + CalculationResult res; + + FixAnalysisAccess access = + new FixAnalysisAccess(artifact); + + if (old instanceof CalculationResult) { + res = (CalculationResult)old; + } + else { + FixAnalysisCalculation calc = new FixAnalysisCalculation(access); + res = calc.calculate(); + } + + if (facets == null) { + return res; + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + FixAnalysisResult fr = (FixAnalysisResult)res.getData(); + if (fr == null) { + return res; + } + + facets.add( + new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id)); + facets.add( + new DataFacet( + FIX_PARAMETERS, "parameters", ComputeType.ADVANCE, hash, id)); + facets.add( + new DataFacet(AT, "AT data", ComputeType.ADVANCE, hash, id)); + + int maxId = -100; + + int sectorMask = fr.getUsedSectorsInAnalysisPeriods(); + + int qsS = access.getQSectorStart(); + int qsE = access.getQSectorEnd(); + + // TODO: i18n + DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); + + DateRange [] periods = access.getAnalysisPeriods(); + + for (int i = 0; i < periods.length; i++) { + DateRange period = periods[i]; + String startDate = df.format(period.getFrom()); + String endDate = df.format(period.getTo()); + + for (int j = qsS; j <= qsE; j++) { + + // Only emit facets for sectors that really have data. + if ((sectorMask & (1 << j)) == 0) { + continue; + } + + String sector = SECTOR_LABELS[j]; + String description = sector + ": " + + startDate + " - " + + endDate; + + int sectorNdx = j - qsS; + int facetNdx = i << 2; + facetNdx = facetNdx | j; + + if (facetNdx > maxId) { + maxId = facetNdx; + } + + facets.add( + new FixAvSectorFacet( + facetNdx, + FIX_SECTOR_AVERAGE_DWT + "_" + sectorNdx, + description)); + facets.add( + new FixLongitudinalAvSectorFacet( + facetNdx, + FIX_SECTOR_AVERAGE_LS + "_" + sectorNdx, + description)); + // TODO: i18n + String dev = "Abweichung: " + description; + facets.add( + new FixLongitudinalAvSectorFacet( + facetNdx, + FIX_SECTOR_AVERAGE_LS_DEVIATION + "_" + sectorNdx, + dev)); + facets.add( + new FixAvSectorFacet( + facetNdx, + FIX_SECTOR_AVERAGE_WQ + "_" + sectorNdx, + description)); + + } + + String eventDesc = + Resources.getMsg(context.getMeta(), + I18N_ANALYSIS, + I18N_ANALYSIS); + + int k = 0; + for (Date d: fr.getAnalysisEventsDates(i)) { + int anaNdx = i << 8; + anaNdx = anaNdx | k; + facets.add(new FixAnalysisEventsFacet(anaNdx, + FIX_ANALYSIS_EVENTS_DWT, + eventDesc + (i+1) + " - " + df.format(d))); + facets.add(new FixLongitudinalAnalysisFacet(anaNdx, + FIX_ANALYSIS_EVENTS_LS, + eventDesc + (i+1) + " - " + df.format(d))); + facets.add(new FixAnalysisEventsFacet(anaNdx, + FIX_ANALYSIS_EVENTS_WQ, + eventDesc + (i+1) +" - " + df.format(d))); + k++; + } + } + + IdGenerator idg = new IdGenerator(maxId + 1); + + String i18n_ref = Resources.getMsg(context.getMeta(), + I18N_REFERENCEPERIOD, + I18N_REFERENCEPERIOD); + String i18n_dev = Resources.getMsg(context.getMeta(), + I18N_REFERENCEDEVIATION, + I18N_REFERENCEDEVIATION); + + int i = 0; + for (Date d: fr.getReferenceEventsDates()) { + int refNdx = idg.next() << 8; + refNdx |= i; + facets.add(new FixReferenceEventsFacet(refNdx, + FIX_REFERENCE_EVENTS_DWT, + i18n_ref + " - " + df.format(d))); + refNdx = idg.next() << 8; + refNdx = refNdx | i; + facets.add(new FixLongitudinalReferenceFacet(refNdx, + FIX_REFERENCE_EVENTS_LS, + i18n_ref + " - " + df.format(d))); + refNdx = idg.next() << 8; + refNdx |= i; + facets.add(new FixReferenceEventsFacet(refNdx, + FIX_REFERENCE_EVENTS_WQ, + i18n_ref + " - " + df.format(d))); + i++; + } + + + facets.add(new FixLongitudinalDeviationFacet(idg.next(), + FIX_DEVIATION_LS, + i18n_dev)); + + String i18n_ana = Resources.getMsg(context.getMeta(), + I18N_ANALYSISPERIODS, + I18N_ANALYSISPERIODS); + facets.add(new FixAnalysisPeriodsFacet(idg.next(), + FIX_ANALYSIS_PERIODS_DWT, + i18n_ana)); + facets.add(new FixAnalysisPeriodsFacet(idg.next(), + FIX_ANALYSIS_PERIODS_LS, + i18n_ana)); + facets.add(new FixAnalysisPeriodsFacet(idg.next(), + FIX_ANALYSIS_PERIODS_WQ, + i18n_ana)); + + + facets.add(new FixWQCurveFacet(idg.next(), "W/Q")); + + Boolean preprocessing = access.getPreprocessing(); + + if (preprocessing != null && preprocessing) { + facets.add(new FixOutlierFacet( + idg.next(), + FIX_OUTLIER, + Resources.getMsg( + context.getMeta(), I18N_OUTLIER, I18N_OUTLIER))); + } + + facets.add(new FixDerivateFacet( + idg.next(), + FIX_DERIVATE, + Resources.getMsg( + context.getMeta(), + I18N_DERIVATIVE, + I18N_DERIVATIVE))); + + facets.add(new FixDeviationFacet( + idg.next(), + FIX_DEVIATION_DWT, + Resources.getMsg(context.getMeta(), + I18N_DEVIATION, + I18N_DEVIATION))); + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,147 @@ +package de.intevation.flys.artifacts.states.fixation; + +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.FixRealizingAccess; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.fixings.FixOutlierFacet; +import de.intevation.flys.artifacts.model.fixings.FixRealizingCalculation; +import de.intevation.flys.artifacts.model.fixings.FixRealizingResult; +import de.intevation.flys.artifacts.model.fixings.FixReferenceEventsFacet; +import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet; +import de.intevation.flys.artifacts.model.fixings.FixWaterlevelFacet; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixRealizingCompute extends DefaultState implements FacetTypes { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(FixRealizingCompute.class); + + + public static final String I18N_WQ_CURVE = "fix.vollmer.wq.curve"; + + public static final String I18N_WQ_OUTLIER = "fix.vollmer.wq.outliers"; + + public static final String I18N_WQ_EVENTS = "fix.vollmer.wq.events"; + + + /** + * The default constructor that initializes an empty State object. + */ + public FixRealizingCompute() { + } + + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + logger.debug("FixRealizingCompute.computeAdvance"); + + CalculationResult res; + + FixRealizingAccess access = + new FixRealizingAccess(artifact); + + if (old instanceof CalculationResult) { + res = (CalculationResult)old; + } + else { + FixRealizingCalculation calc = new FixRealizingCalculation(access); + res = calc.calculate(); + } + + if (facets == null) { + return res; + } + + if (res.getReport().hasProblems()) { + facets.add(new ReportFacet()); + } + + String id = getID(); + CallMeta meta = context.getMeta(); + + FixRealizingResult fixRes = (FixRealizingResult) res.getData(); + WQKms [] wqkms = fixRes != null ? fixRes.getWQKms() : new WQKms[0]; + + for (int i = 0; i < wqkms.length; i++) { + String nameW = null; + String nameQ = null; + + if (access.isQ()) { + nameQ = wqkms[i].getName(); + nameW = "W(" + nameQ + ")"; + } + else { + nameW = wqkms[i].getName(); + nameQ = "Q(" + nameW + ")"; + } + + Facet w = new FixWaterlevelFacet( + i, LONGITUDINAL_W, nameW); + + Facet q = new FixWaterlevelFacet( + i, LONGITUDINAL_Q, nameQ); + + facets.add(w); + facets.add(q); + + if (wqkms[i] instanceof WQCKms) { + String nameC = nameW.replace( + "benutzerdefiniert", + "benutzerdefiniert [korrigiert]"); + + Facet c = new FixWaterlevelFacet( + i, DISCHARGE_LONGITUDINAL_C, nameC); + + facets.add(c); + } + } + + if (wqkms.length > 0) { + facets.add( + new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id)); + + facets.add( + new DataFacet(WST, "WST data", ComputeType.ADVANCE, hash, id)); + + facets.add( + new DataFacet(PDF, "PDF data", ComputeType.ADVANCE, hash, id)); + } + + facets.add(new FixWQCurveFacet( + 0, Resources.getMsg(meta, I18N_WQ_CURVE, I18N_WQ_CURVE))); + + facets.add(new FixReferenceEventsFacet( + 0, + FIX_REFERENCE_EVENTS_WQ, + Resources.getMsg(meta, I18N_WQ_EVENTS, I18N_WQ_EVENTS))); + + facets.add(new FixOutlierFacet( + 0, + FIX_OUTLIER, + Resources.getMsg(meta, I18N_WQ_OUTLIER, I18N_WQ_OUTLIER))); + + return res; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixationPeriod extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(FixationPeriod.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public FixationPeriod() { + } + + @Override + protected String getUIProvider() { + return "fix.period_panel"; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,74 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixationSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(FixationSelect.class); + + + /** Constant value for the default fixation calculation. */ + public static final String CALCULATION_DEFAULT = "calculation.analysis"; + + /** Constant value for the vollmer fixation analysis. */ + public static final String CALCULATION_VOLLMER = "calculation.vollmer"; + + /** An Array that holds all available calculation modes.*/ + public static final String[] CALCULATIONS = { + CALCULATION_DEFAULT, + CALCULATION_VOLLMER + }; + + /** Error message that is thrown if no mode has been chosen. */ + public static final String ERROR_NO_CALCULATION_MODE = + "error_feed_no_calculation_mode"; + + /** Error message that is thrown if an invalid calculation mode has been + * chosen. */ + public static final String ERROR_INVALID_CALCULATION_MODE = + "error_feed_invalid_calculation_mode"; + + + /** + * The default constructor that initializes an empty State object. + */ + public FixationSelect() { + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator ec, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] calculations = new Element[CALCULATIONS.length]; + + for (int i = 0; i < CALCULATIONS.length; i++) { + String calc = CALCULATIONS[i]; + calculations[i] = createItem( + ec, + new String[] {Resources.getMsg(meta, calc, calc), calc}); + } + return calculations; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,61 @@ +package de.intevation.flys.artifacts.states.fixation; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.log4j.Logger; +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FunctionSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(FunctionSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public FunctionSelect() { + } + + @Override + public String getUIProvider() { + return "fix.functionselect"; + } + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator ec, + Artifact artifact, + String name, + CallContext context) + { + FunctionFactory ff = FunctionFactory.getInstance(); + Collection<Function> fc = ff.getFunctions(); + Element[] functions = new Element[fc.size()]; + Iterator<Function> i = fc.iterator(); + + int j = 0; + while(i.hasNext()) { + Function f = i.next(); + String n = f.getName(); + String d = f.getDescription(); + functions[j] = createItem(ec, new String[] {d, n}); + j++; + } + + return functions; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class GaugeRange extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(GaugeRange.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public GaugeRange() { + } + + + @Override + protected String getUIProvider() { + return "fix.gaugeselect_panel"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,72 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; + +import de.intevation.flys.utils.FLYSUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.states.RangeState; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class LocationSelect extends RangeState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(LocationSelect.class); + + private static final String LOWER = "from"; + + private static final String UPPER = "to"; + + private static final String STEP = "step"; + + + /** + * The default constructor that initializes an empty State object. + */ + public LocationSelect() { + } + + @Override + protected String getUIProvider() { + return "fix.location_panel"; + } + + @Override + protected double[] getMinMax(Artifact artifact) { + FLYSArtifact flysArtifact = (FLYSArtifact) artifact; + return FLYSUtils.getRiverMinMax(flysArtifact); + } + + @Override + protected String getLowerField() { + return LOWER; + } + + @Override + protected String getUpperField() { + return UPPER; + } + + @Override + protected String getStepField() { + return STEP; + } + + + /** Misuse to set location mode. */ + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + ((FLYSArtifact) artifact).addStringData("ld_mode", "distance"); + return super.validate(artifact); + } + + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,58 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; + + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class PreprocessingSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(PreprocessingSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public PreprocessingSelect() { + } + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator ec, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] elements = new Element[1]; + elements[0] = createItem( + ec, + new String[] { + Resources.getMsg(meta, + "state.fix.preprocess", + "state.fix.preprocess"), + "preprocess"}); + + return elements; + } + + + @Override + protected String getUIProvider() { + return "fix.preprocessing_panel"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,29 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class QSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(QSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public QSelect() { + } + + + /** Show Q Select Panel in clients. */ + @Override + protected String getUIProvider() { + return "fix.qselect_panel"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,28 @@ +package de.intevation.flys.artifacts.states.fixation; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class ReferencePeriod extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(ReferencePeriod.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public ReferencePeriod() { + } + + @Override + protected String getUIProvider() { + return "fix.period_ref_panel"; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityPeriodsSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,24 @@ +package de.intevation.flys.artifacts.states.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +public class BedQualityPeriodsSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(BedQualityPeriodsSelect.class); + + + /** + * The default constructor that initializes an empty State object. + */ + public BedQualityPeriodsSelect() { + } + + @Override + protected String getUIProvider() { + return "bedquality_periods_select"; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,227 @@ +package de.intevation.flys.artifacts.states.minfo; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.BedQualityAccess; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.minfo.BedDensityFacet; +import de.intevation.flys.artifacts.model.minfo.BedDiameterFacet; +import de.intevation.flys.artifacts.model.minfo.BedDiameterResult; +import de.intevation.flys.artifacts.model.minfo.BedParametersResult; +import de.intevation.flys.artifacts.model.minfo.BedPorosityFacet; +import de.intevation.flys.artifacts.model.minfo.BedQualityCalculation; +import de.intevation.flys.artifacts.model.minfo.BedQualityDiameterResult; +import de.intevation.flys.artifacts.model.minfo.BedQualityResult; +import de.intevation.flys.artifacts.model.minfo.BedloadDiameterFacet; +import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; + + +public class BedQualityState extends DefaultState implements FacetTypes { + + private static final long serialVersionUID = 1L; + + private static final Logger logger = Logger + .getLogger(BedQualityState.class); + + public static final String I18N_TOPLAYER = "bedquality.toplayer"; + public static final String I18N_SUBLAYER = "bedquality.sublayer"; + + public static final String I18N_FACET_BED_POROSITY_TOPLAYER = "facet.bedquality.bed.porosity.toplayer"; + public static final String I18N_FACET_BED_POROSITY_SUBLAYER = "facet.bedquality.bed.porosity.sublayer"; + public static final String I18N_FACET_BED_DENSITY_TOPLAYER = "facet.bedquality.bed.density.toplayer"; + public static final String I18N_FACET_BED_DENSITY_SUBLAYER = "facet.bedquality.bed.density.sublayer"; + public static final String I18N_FACET_BED_DIAMETER_TOPLAYER = "facet.bedquality.bed.diameter.toplayer"; + public static final String I18N_FACET_BED_DIAMETER_SUBLAYER = "facet.bedquality.bed.diameter.sublayer"; + public static final String I18N_FACET_BEDLOAD_DIAMETER = "facet.bedquality.bedload.diameter"; + + @Override + public Object computeAdvance(FLYSArtifact artifact, String hash, + CallContext context, List<Facet> facets, Object old) { + logger.debug("BedQualityState.computeAdvance"); + + List<Facet> newFacets = new ArrayList<Facet>(); + + BedQualityAccess access = new BedQualityAccess(artifact); + + CalculationResult res = old instanceof CalculationResult ? (CalculationResult) old + : new BedQualityCalculation().calculate(access); + + if (facets == null || res == null) { + return res; + } + + BedQualityResult[] results = (BedQualityResult[]) res.getData(); + + if (results == null || results.length == 0) { + logger.warn("Calculation computed no results!"); + return res; + } + + generateFacets(context, newFacets, results, getID(), hash); + logger.debug("Created " + newFacets.size() + " new Facets."); + + facets.addAll(newFacets); + + return res; + } + + protected void generateFacets(CallContext context, List<Facet> newFacets, + BedQualityResult[] results, String stateId, String hash) { + logger.debug("BedQualityState.generateFacets"); + + CallMeta meta = context.getMeta(); + + newFacets.add(new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id)); + for (int idx = 0; idx < results.length; idx++) { + BedQualityResult result = results[idx]; + DateRange range = result.getDateRange(); + BedDiameterResult[] bedDiameter = result.getBedResults(); + for (int j = 0; j < bedDiameter.length; j++) { + newFacets.add(new BedDiameterFacet((idx << 8) + j, + BED_QUALITY_BED_DIAMETER_TOPLAYER, + createDiameterTopLayerDescription( + meta, + bedDiameter[j], + range), + ComputeType.ADVANCE, stateId, hash)); + + newFacets.add(new BedDiameterFacet((idx << 8) +j, + BED_QUALITY_BED_DIAMETER_SUBLAYER, + createDiameterSubLayerDescription( + meta, + bedDiameter[j], + range), + ComputeType.ADVANCE, stateId, hash)); + } + BedloadDiameterResult[] bedloadDiameter = result.getBedloadResults(); + for (int j = 0; j < bedloadDiameter.length; j++) { + newFacets.add(new BedloadDiameterFacet( + (idx << 8) + j, + BED_QUALITY_BEDLOAD_DIAMETER, + createDiameterDescription( + meta, bedloadDiameter[j]), + ComputeType.ADVANCE, + stateId, + hash)); + + } + BedParametersResult[] bedParameters = result.getParameters(); + for (int j = 0; j < bedParameters.length; j++) { + newFacets.add(new BedPorosityFacet((idx << 8) + j, + BED_QUALITY_POROSITY_TOPLAYER, + createPorosityTopLayerDescription( + meta, + bedParameters[j], + range), + ComputeType.ADVANCE, stateId, hash)); + + newFacets.add(new BedPorosityFacet((idx << 8) + j, + BED_QUALITY_POROSITY_SUBLAYER, + createPorositySubLayerDescription( + meta, + bedParameters[j], + range), + ComputeType.ADVANCE, stateId, hash)); + + newFacets.add(new BedDensityFacet((idx << 8) + j, + BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER, + createDensityTopLayerDescription( + meta, + bedParameters[j], + range), + ComputeType.ADVANCE, stateId, hash)); + + newFacets.add(new BedDensityFacet((idx << 8) + j, + BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER, + createDensitySubLayerDescription( + meta, + bedParameters[j], + range), + ComputeType.ADVANCE, stateId, hash)); + } + } + } + + protected String createPorosityTopLayerDescription(CallMeta meta, + BedParametersResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER); + return Resources.getMsg(meta, I18N_FACET_BED_POROSITY_TOPLAYER, + I18N_FACET_BED_POROSITY_TOPLAYER, new Object[] { from, to, toplayer }); + } + + protected String createPorositySubLayerDescription(CallMeta meta, + BedParametersResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER); + return Resources.getMsg(meta, I18N_FACET_BED_POROSITY_SUBLAYER, + I18N_FACET_BED_POROSITY_SUBLAYER, new Object[] { from, to, sublayer }); + } + + protected String createDensityTopLayerDescription(CallMeta meta, + BedParametersResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER); + return Resources.getMsg(meta, I18N_FACET_BED_DENSITY_TOPLAYER, + I18N_FACET_BED_DENSITY_TOPLAYER, new Object[] { from, to, toplayer }); + } + + protected String createDensitySubLayerDescription(CallMeta meta, + BedParametersResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER); + return Resources.getMsg(meta, I18N_FACET_BED_DENSITY_SUBLAYER, + I18N_FACET_BED_DENSITY_SUBLAYER, new Object[] { from, to, sublayer }); + } + + protected String createDiameterTopLayerDescription(CallMeta meta, + BedDiameterResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER); + + return Resources.getMsg(meta, I18N_FACET_BED_DIAMETER_TOPLAYER, + I18N_FACET_BED_DIAMETER_TOPLAYER, new Object[] { result.getType(), + from, to, toplayer }); + } + + protected String createDiameterSubLayerDescription(CallMeta meta, + BedDiameterResult result, DateRange range) { + Date from = range != null ? range.getFrom() : new Date(); + Date to = range != null ? range.getTo() : new Date(); + + String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER); + return Resources.getMsg(meta, I18N_FACET_BED_DIAMETER_SUBLAYER, + I18N_FACET_BED_DIAMETER_SUBLAYER, new Object[] { result.getType(), + from, to, sublayer }); + } + + protected String createDiameterDescription(CallMeta meta, + BedQualityDiameterResult result) { + return Resources.getMsg(meta, I18N_FACET_BEDLOAD_DIAMETER, + I18N_FACET_BEDLOAD_DIAMETER, new Object[] { result.getType() }); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,88 @@ +package de.intevation.flys.artifacts.states.minfo; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.model.KVP; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.MultiStringArrayState; + +public class CharDiameter extends MultiStringArrayState { + + private static final Logger logger = Logger.getLogger(CharDiameter.class); + + public static final String UI_PROVIDER = "parameter-matrix"; + + private static final String CHAR_DIAMETER_MIN = "calc.bed.dmin"; + private static final String CHAR_DIAMETER_MAX = "calc.bed.dmax"; + private static final String CHAR_DIAMETER_90 = "calc.bed.d90"; + private static final String CHAR_DIAMETER_84 = "calc.bed.d84"; + private static final String CHAR_DIAMETER_80 = "calc.bed.d80"; + private static final String CHAR_DIAMETER_75 = "calc.bed.d75"; + private static final String CHAR_DIAMETER_70 = "calc.bed.d70"; + private static final String CHAR_DIAMETER_60 = "calc.bed.d60"; + private static final String CHAR_DIAMETER_50 = "calc.bed.d50"; + private static final String CHAR_DIAMETER_40 = "calc.bed.d40"; + private static final String CHAR_DIAMETER_30 = "calc.bed.d30"; + private static final String CHAR_DIAMETER_25 = "calc.bed.d25"; + private static final String CHAR_DIAMETER_20 = "calc.bed.d20"; + private static final String CHAR_DIAMETER_16 = "calc.bed.d16"; + private static final String CHAR_DIAMETER_10 = "calc.bed.d10"; + + public static final String[] CHAR_DIAMETER = { + CHAR_DIAMETER_10, + CHAR_DIAMETER_16, + CHAR_DIAMETER_20, + CHAR_DIAMETER_25, + CHAR_DIAMETER_30, + CHAR_DIAMETER_40, + CHAR_DIAMETER_50, + CHAR_DIAMETER_60, + CHAR_DIAMETER_70, + CHAR_DIAMETER_75, + CHAR_DIAMETER_80, + CHAR_DIAMETER_84, + CHAR_DIAMETER_90, + CHAR_DIAMETER_MAX, + CHAR_DIAMETER_MIN + }; + + @Override + public String getUIProvider() { + return UI_PROVIDER; + } + + @Override + protected KVP<String, String>[] getOptions( + Artifact artifact, + String parameterName, + CallContext context + ) + throws IllegalArgumentException + { + CallMeta meta = context.getMeta(); + + List<KVP<String, String>> rows = new ArrayList<KVP<String, String>>(); + String key = parameterName; + for (int i = 0; i < CHAR_DIAMETER.length; ++i) { + String calc = CHAR_DIAMETER[i]; + rows.add(new KVP (calc, + Resources.getMsg(meta, calc, calc))); + } + + return rows.toArray(new KVP[rows.size()]); + } + + @Override + protected String getLabelFor(CallContext cc, String parameterName, + String value) throws IllegalArgumentException { + + return Resources.getMsg(cc.getMeta(), value, value); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,139 @@ +package de.intevation.flys.artifacts.states.minfo; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Element; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.BedHeightAccess; +import de.intevation.flys.artifacts.states.DefaultState; +import de.intevation.flys.utils.StringUtil; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class DifferenceSelect extends DefaultState { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(DifferenceSelect.class); + + /** + * The default constructor that initializes an empty State object. + */ + public DifferenceSelect() { + } + /** + * Specify to display nothing (this is kind of a "final" state). + */ + @Override + protected String getUIProvider() { + return "bedheights_twin_panel"; + } + + /** + * Overridden to do nothing. + */ + @Override + public Object computeAdvance( + FLYSArtifact artifact, + String hash, + CallContext context, + List<Facet> facets, + Object old + ) { + //Get data and do stuff, do not calculate + return ""; + } + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator ec, + Artifact artifact, + String name, + CallContext context) + { + Element[] elements = new Element[1]; + BedHeightAccess bha = new BedHeightAccess((FLYSArtifact)artifact); + String time = bha.getYearEpoch(); + elements[0] = createItem( + ec, + new String[] {"year-epoch", time}); + + return elements; + } + + /** + * Creates the data element used for the static part of DESCRIBE document. + */ + @Override + protected Element createStaticData( + FLYSArtifact flys, + ElementCreator creator, + CallContext cc, + String name, + String value, + String type + ) { + Element dataElement = creator.create("data"); + creator.addAttr(dataElement, "name", name, true); + creator.addAttr(dataElement, "type", type, true); + + Element itemElement = creator.create("item"); + creator.addAttr(itemElement, "value", value, true); + + String[] labels = getLabels(cc, value); + + creator.addAttr( + itemElement, + "label", + labels[0], + true); + dataElement.appendChild(itemElement); + + return dataElement; + } + + + /** + * Get name to display for selected watelerlevels (for example "Q=123") + * from the CalculationResult. + */ + public static String[] getLabels(CallContext cc, String value) { + String[] recommendations = value.split("#"); + String displayString = ""; + + // Walk over all selected recommendations and create label + for (int i = 0; i < recommendations.length; i+=2) { + String[] minuendParts = StringUtil + .unbracket(recommendations[i+0]) + .split(";"); + if(minuendParts.length >= 4) { + displayString += "(" + minuendParts[3]; + } + else { + displayString += "([error]"; + } + + displayString += " - "; + + String[] subtrahendParts = StringUtil + .unbracket(recommendations[i+1]) + .split(";"); + if(subtrahendParts.length >= 4) { + displayString += subtrahendParts[3] + ") "; + } + else { + displayString += "[error])"; + } + } + + return new String[] { displayString }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +package de.intevation.flys.artifacts.states.minfo; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class DifferencesState extends DefaultState { + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(DifferencesState.class); + + public DifferencesState() { + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,59 @@ +package de.intevation.flys.artifacts.states.minfo; + +import org.apache.log4j.Logger; +import org.w3c.dom.Element; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class YearEpochSelect extends DefaultState { + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(YearEpochSelect.class); + + /** + * The default constructor that initializes an empty State object. + */ + public YearEpochSelect() { + } + + @Override + protected String getUIProvider() { + return "minfo.bed.year_epoch"; + } + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator ec, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + Element[] elements = new Element[2]; + elements[0] = createItem( + ec, + new String[] { + Resources.getMsg(meta, + "state.minfo.year", + "state.minfo.year"), + "year"}); + + elements[1] = createItem( + ec, + new String[] { + Resources.getMsg(meta, + "state.minfo.epoch", + "state.minfo.epoch"), + "epoch"}); + + return elements; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/sq/SQPeriodSelect.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.artifacts.states.sq; + +import de.intevation.flys.artifacts.states.PeriodsSelect; + +public class SQPeriodSelect extends PeriodsSelect { + + public static final String UI_PROVIDER = "sq.period.select"; + + private static final long serialVersionUID = 1L; + + + @Override + public String getUIProvider() { + return UI_PROVIDER; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,104 @@ +package de.intevation.flys.artifacts.transitions; + +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifactdatabase.state.State; +import de.intevation.artifactdatabase.transition.Transition; + + +/** + * The default implementation of a <code>Transition</code>. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DefaultTransition implements Transition { + + /** The ID of the current state */ + protected String from; + + /** The ID of the target state */ + protected String to; + + + /** + * The default constructor. + */ + public DefaultTransition() { + } + + + /** + * The default constructor. + * + * @param from The current state. + * @param to The target state. + */ + public DefaultTransition(String from, String to) { + this.from = from; + this.to = to; + } + + + public void init(Node config) { + // nothing to do in the default transition + } + + + /** + * Returns the current state ID. + * + * @return the current state ID. + */ + public String getFrom() { + return from; + } + + + /** + * Returns the target state ID. + * + * @return the target state ID. + */ + public String getTo() { + return to; + } + + + /** + * Set the current state ID. + * + * @param from current state ID. + */ + public void setFrom(String from) { + this.from = from; + } + + + /** + * Set the target state ID. + * + * @param to the target state ID. + */ + public void setTo(String to) { + this.to = to; + } + + + /** + * Determines if its valid to step from state <i>a</i> of an artifact + * <i>artifact</i> to state <i>b</i>. This method always returns true - no + * validation takes place. + * + * @param artifact The owner artifact of state a and b. + * @param a The current state. + * @param b The target state. + * + * @return true, if it is valid to step from a to b, otherwise false. + */ + public boolean isValid(Artifact artifact, State a, State b) { + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/transitions/TransitionFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,71 @@ +package de.intevation.flys.artifacts.transitions; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.transition.Transition; + +import de.intevation.artifacts.common.utils.XMLUtils; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class TransitionFactory { + + /** The logger used in this class */ + private static Logger logger = Logger.getLogger(TransitionFactory.class); + + /** The XPath to the classname of the transition */ + public static final String XPATH_TRANSITION = "@transition"; + + /** The XPath to the current state ID */ + public static final String XPATH_CURRENT_STATE = "from/@state"; + + /** The XPath to the target state ID */ + public static final String XPATH_TARGET_STATE = "to/@state"; + + + /** + * Creates a new Transition based on the configured class provided by + * <code>transitionConf</code>. + * + * @param transitionConf The configuration of the transition. + * + * @return a Transition. + */ + public static Transition createTransition(Node transitionConf) { + String clazz = (String) XMLUtils.xpath( + transitionConf, XPATH_TRANSITION, XPathConstants.STRING); + + Transition transition = null; + + try { + transition = (Transition) Class.forName(clazz).newInstance(); + + String from = (String) XMLUtils.xpath( + transitionConf, XPATH_CURRENT_STATE, XPathConstants.STRING); + String to = (String) XMLUtils.xpath( + transitionConf, XPATH_TARGET_STATE, XPathConstants.STRING); + + transition.init(transitionConf); + transition.setFrom(from); + transition.setTo(to); + } + catch (InstantiationException ie) { + logger.error(ie, ie); + } + catch (IllegalAccessException iae) { + logger.error(iae, iae); + } + catch (ClassNotFoundException cnfe) { + logger.error(cnfe, cnfe); + } + + return transition; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/transitions/ValueCompareTransition.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,118 @@ +package de.intevation.flys.artifacts.transitions; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; + +import de.intevation.artifacts.Artifact; + +import de.intevation.artifactdatabase.data.StateData; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.FLYSArtifact; + + +/** + * This transition compares data objects with a <i>equal</i> or <i>notequal</i> + * operator. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ValueCompareTransition extends DefaultTransition { + + /** The logger that is used in this transition.*/ + private static Logger log = Logger.getLogger(ValueCompareTransition.class); + + + /** XPath that points to the condition's operator.*/ + public static final String XPATH_OPERATOR = "condition/@operator"; + + /** XPath that points to the condition's value.*/ + public static final String XPATH_VALUE = "condition/@value"; + + /** XPath that points to the condition's dataname.*/ + public static final String XPATH_DATANAME = "condition/@data"; + + /** The value of the 'equal' operator.*/ + public static final String OPERATOR_EQUAL = "equal"; + + /** The value of the 'not equal' operator.*/ + public static final String OPERATOR_NOTEQUAL = "notequal"; + + + /** The operator.*/ + protected String operator; + + /** The value used for comparison.*/ + protected String value; + + /** The name of the data used for the comparison.*/ + protected String dataname; + + + + public ValueCompareTransition() { + } + + + public ValueCompareTransition(String from, String to) { + super(from, to); + } + + + @Override + public void init(Node config) { + log.debug("ValueCompareTransition.init"); + + String tmp = (String) XMLUtils.xpath( + config, + XPATH_OPERATOR, + XPathConstants.STRING); + operator = tmp.trim().toLowerCase(); + + value = (String) XMLUtils.xpath( + config, + XPATH_VALUE, + XPathConstants.STRING); + + dataname = (String) XMLUtils.xpath( + config, + XPATH_DATANAME, + XPathConstants.STRING); + } + + + @Override + public boolean isValid(Artifact artifact, State a, State b) { + log.debug("ValueCompareTransition.isValid"); + + FLYSArtifact flysArtifact = (FLYSArtifact) artifact; + + StateData dataObj = flysArtifact.getData(dataname); + String dataVal = dataObj != null ? (String) dataObj.getValue() : ""; + + if (log.isDebugEnabled()) { + log.debug("Compare settings:"); + log.debug("-- dataname: " + dataname); + log.debug("-- operator: " + operator); + log.debug("-- compare value: " + value); + log.debug("-- state value: " + dataVal); + } + + if (operator.equals(OPERATOR_EQUAL)) { + return value.equals(dataVal); + } + else if (operator.equals(OPERATOR_NOTEQUAL)) { + return !(value.equals(dataVal)); + } + + log.error("Wrong operator set! No comparison takes place."); + + return false; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeParser.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,167 @@ +package de.intevation.flys.collections; + +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifacts.ArtifactNamespaceContext; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.Settings; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.model.ManagedDomFacet; +import de.intevation.flys.exports.ChartSettings; + +/** + * Access parts of the Attribute parts of a FLYSCollections description + * document. + */ +public class AttributeParser { + + /** Constant XPath that points to the outputmodes of an artifact. */ + public static final String XPATH_ARTIFACT_OUTPUTMODES = + "/art:attribute/art:outputs/art:output"; + + + private static Logger logger = Logger.getLogger(AttributeParser.class); + + + protected Document attributeDocument; + + protected CollectionAttribute attribute; + + + public AttributeParser(Document attributeDocument) { + this.attributeDocument = attributeDocument; + } + + + public void parse() { + logger.debug("AttributeParser.parse"); + + attribute = new CollectionAttribute(); + + NodeList outs = (NodeList) XMLUtils.xpath( + attributeDocument, + XPATH_ARTIFACT_OUTPUTMODES, + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + int num = outs != null ? outs.getLength() : 0; + + logger.debug("Attribute has " + num + " outputs."); + + for (int i = 0; i < num; i++) { + Node out = outs.item(i); + + parseOutput(out); + } + } + + + public CollectionAttribute getCollectionAttribute() { + if (attribute == null) { + parse(); + } + + return attribute; + } + + + public Document getAttributeDocument() { + return attributeDocument; + } + + + public Map<String, Output> getOuts() { + return attribute.getOutputs(); + } + + + /** + * Access all facets. + * @return list of all facets. + */ + public List<Facet> getFacets() { + return attribute.getFacets(); + } + + + protected void parseOutput(Node out) { + String name = ((Element)out).getAttribute("name"); + + if (name.length() == 0) { + logger.warn("No Output name specified. Cancel parsing!"); + return; + } + + Output o = attribute.getOutput(name); + + if (o == null) { + logger.debug("Create new output: " + name); + + o = new DefaultOutput(name, null, null); + attribute.addOutput(name, o); + } + + parseSettings(out, name); + parseItems(out, name); + } + + private static final Node getChild(Element element, String name) { + NodeList children = element.getChildNodes(); + for (int i = 0, N = children.getLength(); i < N; ++i) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE + && child.getLocalName().equals(name)) { + return child; + } + } + return null; + } + + + protected void parseSettings(Node out, String outname) { + Node settingsNode = getChild((Element)out, "settings"); + + if (settingsNode == null) { + logger.debug("No Settings found for Output '" + outname + "'"); + return; + } + + Settings settings = ChartSettings.parse(settingsNode); + attribute.setSettings(outname, settings); + } + + + protected void parseItems(Node out, String outname) { + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + Element element = (Element)out; + + NodeList themes = element.getElementsByTagNameNS(uri, "facet"); + + int num = themes.getLength(); + + logger.debug("Output has " + num + " themes."); + + for (int i = 0; i < num; i++) { + Element theme = (Element) themes.item(i); + if (theme.getParentNode() == out) { + attribute.addFacet(outname, new ManagedDomFacet(theme)); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,307 @@ +package de.intevation.flys.collections; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.FacetActivity; +import de.intevation.artifactdatabase.state.Output; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.ManagedFacet; + +/** + * Create attribute- element of describe document of an ArtifactCollection. + * The attribute-element contains the merged output of all outputmodes and + * facets that are part of the collection. + */ +public class AttributeWriter { + + /** ArtifactDatabase used to fetch Artifacts. */ + protected ArtifactDatabase db = null; + + protected Map<String, Output> oldAttr; + + protected Map<String, Output> newAttr; + + /** List of already seen facets. */ + protected List<Facet> oldFacets; + + /** List of "new" facets. */ + protected List<Facet> newFacets; + + /** + * "Compatibility matrix", mapws list of facet names to output names. + * Any facet that is not found in the list for a specific output will + * not be added to the resulting document. + */ + protected Map<String, List<String>> compatibilities; + + + /** The result of the <i>write()</i> operation.*/ + protected CollectionAttribute attribute; + + + private static Logger logger = Logger.getLogger(AttributeWriter.class); + + + /** + * Create a AttributeWriter. + * Attributes not present in newAttr will not be included in the document. + * @param db Database to fetch artifacts. + * @param oldAttr "Old" (possibly user-changed) outputs. + * @param newAttr "New" (eventually re-read in its original, unchanged + * form) outputs. + */ + public AttributeWriter( + ArtifactDatabase db, + CollectionAttribute attribute, + Map<String, Output> oldAttr, + List<Facet> oldFacets, + Map<String, Output> newAttr, + List<Facet> newFacets, + Map<String, List<String>> matrix) + { + this.db = db; + this.attribute = attribute; + this.oldAttr = oldAttr; + this.newAttr = newAttr; + this.oldFacets = oldFacets; + this.newFacets = newFacets; + this.compatibilities = matrix; + } + + + /** + * Create document by merging outputs given in + * constructor. + * + * The "new" set rules about existance of attributes, so anything not + * present in it will not be included in the resulting document. + * The "old" set rules about the content of attributes (as user changes + * are recorded here and not in the new set). + * + * @return document with merged outputs as described. + */ + protected CollectionAttribute write() { + + boolean debug = logger.isDebugEnabled(); + + for (Map.Entry<String, Output> entry: newAttr.entrySet()) { + String outName = entry.getKey(); + Output a = entry.getValue(); + + Output exists = attribute.getOutput(outName); + if (exists == null) { + attribute.addOutput(outName, a); + } + + attribute.clearFacets(outName); + + if (debug) { + logger.debug("Merge Output: " + outName); + logger.debug(" old Facets: " + oldFacets.size()); + logger.debug(" new Facets: " + newFacets.size()); + } + + writeOutput(a.getName(), newFacets, oldFacets); + } + + // THIS CALL IS ABSOLUTELY NECESSARY! + attribute.cleanEmptyOutputs(); + + return attribute; + } + + + /** + * @param outputName the "new" outputs name + * @param newOutFacets Facets of the new outputs + * @param oldOutFacets Facets of the old outputs (can be null) + */ + protected void writeOutput( + String outputName, + List<Facet> newOutFacets, + List<Facet> oldOutFacets + ) { + List<String> compatFacets = this.compatibilities.get(outputName); + + if (logger.isDebugEnabled() && compatFacets != null) { + logger.debug("Compabitle Facets:"); + for (String compatible: compatFacets) { + logger.debug( "- " + compatible); + } + } + + try { + writeFacets(outputName, newOutFacets, oldOutFacets, compatFacets); + } + catch (ArtifactDatabaseException ade) { + logger.error(ade, ade); + } + } + + + /** + * @param newFacets the new facets + * @param oldFacets the old facets + * @param compatibleFacets List of facets to accept + * @return true if any facets are written to the out. + */ + protected boolean writeFacets( + String outputName, + List<Facet> newFacets, + List<Facet> oldFacets, + List<String> compatibleFacets) + throws ArtifactDatabaseException + { + if (compatibleFacets == null) { + logger.warn("No compatible facets, not generating out."); + return false; + } + + int num = newFacets.size(); + + // Add all new Facets either in their old state or (if really + // new) as they are. + List<ManagedFacet> currentFacets = new ArrayList<ManagedFacet>(); + List<ManagedFacet> genuinelyNewFacets = new ArrayList<ManagedFacet>(); + + boolean debug = logger.isDebugEnabled(); + + for (int i = 0; i < num; i++) { + ManagedFacet facet = (ManagedFacet) newFacets.get(i); + + if (debug) { + logger.debug("Try to add Facet: " + facet.getName()); + } + + if (!compatibleFacets.contains(facet.getName())) { + //logger.debug("Have incompatible facet, skip: " + facet.getName()); + continue; + } + //else logger.debug("Have compatible facet: " + facet.getName()); + + ManagedFacet picked = pickFacet(facet, oldFacets); + + if (facet.equals(picked)) { + genuinelyNewFacets.add(picked); + } + else { + currentFacets.add(picked); + } + } + + FacetActivity.Registry registry = FacetActivity.Registry.getInstance(); + + // With each genuinely new Facet, figure out whether it comes to live + // in/activate. + for (ManagedFacet newMF: genuinelyNewFacets) { + FLYSArtifact flys = + (FLYSArtifact)db.getRawArtifact(newMF.getArtifact()); + + boolean isActive = registry.isInitialActive( + flys.getName(), flys, newMF, outputName); + + newMF.setActive(isActive ? 1 : 0); + } + + // For each genuinely new Facet check positional conflicts. + for (ManagedFacet newMF: genuinelyNewFacets) { + boolean conflicts = true; + // Loop until all conflicts resolved. + while (conflicts) { + conflicts = false; + for (ManagedFacet oldMF: currentFacets) { + if (newMF.getPosition() == oldMF.getPosition()) { + conflicts = true; + if (debug) { + logger.debug( + "Positional conflict while merging " + + "facets, pushing newest facet 1 up (" + + newMF.getPosition() + ")"); + } + newMF.setPosition(newMF.getPosition() + 1); + break; + } + } + } + currentFacets.add(newMF); + } + + // Fill/correct "gaps" (e.g. position 1,2,5 are taken, after gap filling + // expect positions 1,2,3 [5->3]) + // Preparations to be able to detect gaps. + Map<Integer, ManagedFacet> mfmap = + new HashMap<Integer, ManagedFacet>(); + int max = 0; + for (ManagedFacet mf: currentFacets) { + int pos = mf.getPosition(); + mfmap.put(Integer.valueOf(pos), mf); + if (pos > max) max = pos; + } + + // Finally do gap correction. + if (max != currentFacets.size()) { + int gap = 0; + for (int i = 1; i <= max; i++) { + ManagedFacet mf = mfmap.get(Integer.valueOf(i)); + if (mf == null) { + gap++; + continue; + } + mf.setPosition(mf.getPosition() - gap); + } + } + + // Now add all facets. + for (ManagedFacet oldMF: currentFacets) { + attribute.addFacet(outputName, oldMF); + } + + return !currentFacets.isEmpty(); + } + + + /** + * Returns the facet to be added to Document. + * Return the new facet only if the "same" facet was not present before. + * Return the "old" facet otherwise (user-defined information sticks + * to it). + * @param facet the new facet. + * @param oldFacets the old facets, new facet is compared against each of + * these. + * @return facet if genuinely new, matching old facet otherwise. + */ + protected ManagedFacet pickFacet(ManagedFacet facet, List<Facet> oldFacets) + { + if (oldFacets == null) { + logger.debug("No old facets to compare a new to found."); + return facet; + } + + String hash = facet.getName() + facet.getIndex() + facet.getArtifact(); + + // Compare "new" facet with all old facets. + // Take oldFacet if that facet was already present (otherwise + // information is lost, the new one otherwise. + for (Facet oFacet: oldFacets) { + ManagedFacet oldFacet = (ManagedFacet) oFacet; + String oldHash = oldFacet.getName() + + oldFacet.getIndex() + + oldFacet.getArtifact(); + if (hash.equals(oldHash)) { + return oldFacet; + } + } + return facet; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,314 @@ +package de.intevation.flys.collections; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.ArtifactNamespaceContext; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.Settings; + + +/** Create attribute part of collection document. */ +public class CollectionAttribute { + + private static final Logger logger = + Logger.getLogger(CollectionAttribute.class); + + protected ElementCreator ec; + + protected Map<String, Output> outputMap; + + protected Node loadedRecommendations; + + + public CollectionAttribute() { + } + + + public void addOutput(String key, Output output) { + if (outputMap == null) { + outputMap = new HashMap<String, Output>(); + } + + if (key != null && key.length() > 0 && output != null) { + outputMap.put( + key, + new DefaultOutput( + output.getName(), + output.getDescription(), + output.getMimeType(), + new ArrayList<Facet>(), + output.getType())); + } + } + + + public void cleanEmptyOutputs() { + if (outputMap == null) { + return; + } + + List<String> removeUs = new ArrayList<String>(); + + Set<Map.Entry<String, Output>> entries = outputMap.entrySet(); + for (Map.Entry<String, Output> entry: entries) { + Output o = entry.getValue(); + + List<Facet> facets = o.getFacets(); + if (facets == null || facets.isEmpty()) { + removeUs.add(entry.getKey()); + } + } + + for (String key: removeUs) { + outputMap.remove(key); + } + } + + + public void setSettings(String outputKey, Settings settings) { + if (settings == null) { + logger.warn("Tried to set empty Settings for '" + outputKey + "'"); + return; + } + + if (outputMap == null) { + logger.warn("Tried to add facet but no Outputs are existing yet."); + return; + } + + Output output = outputMap.get(outputKey); + + if (output == null) { + logger.warn("Tried to add facet for unknown Output: " + outputKey); + return; + } + + output.setSettings(settings); + } + + + public void addFacet(String outputKey, Facet facet) { + if (facet == null) { + logger.warn("Tried to add empty facet."); + return; + } + + if (outputMap == null) { + logger.warn("Tried to add facet but no Outputs are existing yet."); + return; + } + + Output output = outputMap.get(outputKey); + + if (output == null) { + logger.warn("Tried to add facet for unknown Output: " + outputKey); + return; + } + + logger.debug("Add facet for '" + outputKey + "': " + facet.getName()); + output.addFacet(facet); + } + + + public void setLoadedRecommendations(Node loadedRecommendations) { + // TODO Replace this Node with a Java class object. + this.loadedRecommendations = loadedRecommendations; + } + + + public void clearFacets(String outputKey) { + if (outputKey == null || outputKey.length() == 0) { + logger.warn("Tried to clear Facets, but no Output key specified!"); + return; + } + + if (outputMap == null) { + logger.warn("Tried to clear Facets, but no Outputs existing!"); + return; + } + + Output output = outputMap.get(outputKey); + if (output == null) { + logger.warn("Tried to clear Facets for unknown Out: " + outputKey); + return; + } + + output.setFacets(new ArrayList<Facet>()); + } + + + public Document toXML() { + Document doc = XMLUtils.newDocument(); + + ec = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = ec.create("attribute"); + + appendOutputs(root); + appendLoadedRecommendations(root); + + doc.appendChild(root); + + return doc; + } + + + public Map<String, Output> getOutputs() { + return outputMap; + } + + + public Output getOutput(String name) { + if (name == null || name.length() == 0) { + logger.warn("No Output name specified."); + return null; + } + + if (outputMap == null || outputMap.isEmpty()) { + logger.warn("Tried to retrieve Output, but no Outputs existing."); + return null; + } + + return outputMap.get(name); + } + + + public List<Facet> getFacets(String output) { + if (output == null || output.length() == 0) { + logger.warn("No Output name specified."); + return new ArrayList<Facet>(); + } + + if (outputMap == null) { + logger.warn("Tried to retrieve facets, but no Outputs existing."); + return new ArrayList<Facet>(); + } + + Output o = outputMap.get(output); + + if (o == null) { + logger.warn("No Output '" + output + "' existing."); + return new ArrayList<Facet>(); + } + + return o.getFacets(); + } + + + public List<Facet> getFacets() { + List<Facet> allFacets = new ArrayList<Facet>(); + + if (outputMap == null || outputMap.isEmpty()) { + logger.warn("No Outputs existing."); + return allFacets; + } + + Set<String> outputNames = outputMap.keySet(); + + for (String outputName: outputNames) { + allFacets.addAll(getFacets(outputName)); + } + + return allFacets; + } + + + protected void appendOutputs(Element root) { + if (outputMap == null || outputMap.isEmpty()) { + logger.warn("No outputs to append."); + return; + } + + logger.debug("Append " + outputMap.size() + " Output Elements."); + + Element outputsEl = ec.create("outputs"); + + Set<Map.Entry<String, Output>> entrySet = outputMap.entrySet(); + + for (Map.Entry<String, Output> entry: entrySet) { + appendOutput(outputsEl, entry.getKey(), entry.getValue()); + } + + root.appendChild(outputsEl); + } + + + protected void appendOutput(Element root, String name, Output output) { + if (name == null || name.length() == 0 || output == null) { + logger.warn("Tried to appendOutput, but Output is invalid."); + return; + } + + logger.debug("Append Output Element for '" + name + "'"); + + Element outputEl = ec.create("output"); + ec.addAttr(outputEl, "name", name); + + appendSettings(outputEl, output.getSettings()); + appendFacets(outputEl, output.getFacets()); + + root.appendChild(outputEl); + } + + + protected void appendSettings(Element root, Settings settings) { + if (settings == null) { + logger.warn("Tried to append Settings, but Settings is empty!"); + return; + } + + settings.toXML(root); + } + + + protected void appendFacets(Element root, List<Facet> facets) { + if (facets == null || facets.isEmpty()) { + logger.warn("Tried to append 0 Facets."); + return; + } + + Document owner = root.getOwnerDocument(); + + logger.debug("Append " + facets.size() + " facets."); + + for (Facet facet: facets) { + Node facetNode = facet.toXML(owner); + + if (facetNode != null) { + root.appendChild(facetNode); + } + } + } + + + protected void appendLoadedRecommendations(Element root) { + if (loadedRecommendations == null) { + logger.debug("No loaded recommendations existing yet."); + return; + } + + Document owner = root.getOwnerDocument(); + + root.appendChild(owner.importNode(loadedRecommendations, true)); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,203 @@ +package de.intevation.flys.collections; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + + +public class CollectionDescriptionHelper { + + private static final Logger logger = + Logger.getLogger(CollectionDescriptionHelper.class); + + + public static final String XPATH_ARTIFACT_STATE_DATA = + "/art:result/art:ui/art:static/art:state/art:data"; + + /** Constant XPath that points to the outputmodes of an artifact. */ + public static final String XPATH_ARTIFACT_OUTPUTMODES = + "/art:result/art:outputmodes"; + + + protected ElementCreator ec; + + protected CallContext context; + protected ArtifactDatabase database; + + protected String name; + protected String uuid; + protected Date creation; + protected long ttl; + + protected List<String> artifacts; + protected CollectionAttribute attribute; + + + /** + * @param name The name of the collection. + * @param uuid The uuid of the collection. + * @param creation The creation time of the collection. + * @param ttl The time to live of the collection. + */ + public CollectionDescriptionHelper( + String name, + String uuid, + Date creation, + long ttl, + CallContext callContext + ) { + this.name = name; + this.uuid = uuid; + this.creation = creation; + this.ttl = ttl; + this.context = callContext; + this.database = callContext.getDatabase(); + this.artifacts = new ArrayList<String>(); + } + + + public void addArtifact(String uuid) { + if (uuid != null && uuid.length() > 0) { + artifacts.add(uuid); + } + } + + + public void setAttribute(CollectionAttribute attribute) { + if (attribute != null) { + this.attribute = attribute; + } + } + + + public Document toXML() { + Document doc = XMLUtils.newDocument(); + + ec = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = ec.create("artifact-collection"); + doc.appendChild(root); + + String creationTime = creation != null + ? Long.toString(creation.getTime()) + : ""; + + ec.addAttr(root, "name", name, true); + ec.addAttr(root, "uuid", uuid, true); + ec.addAttr(root, "creation", creationTime, true); + ec.addAttr(root, "ttl", String.valueOf(ttl), true); + + appendArtifacts(root); + appendAttribute(root); + + return doc; + } + + + /** + * Appends parts of the DESCRIBE document of each Artifact to <i>root</i>. + * + * @param root The root node. + */ + protected void appendArtifacts(Element root) { + Element artifactsEl = ec.create("artifacts"); + + for (String uuid: artifacts) { + try { + Element e = buildArtifactNode(uuid); + + if (e != null) { + artifactsEl.appendChild(e); + } + } + catch (ArtifactDatabaseException dbe) { + logger.warn(dbe, dbe); + } + } + + root.appendChild(artifactsEl); + } + + + /** + * Create the Artifacts Node that contains outputmode and statedata. + * + * @param uuid uuid of the artifact. + */ + protected Element buildArtifactNode(String uuid) + throws ArtifactDatabaseException + { + logger.debug("Append artifact '" + uuid + "' to collection description"); + + // TODO + String hash = "MYHASH"; + + Element ci = ec.create("artifact"); + ec.addAttr(ci, "uuid", uuid, true); + ec.addAttr(ci, "hash", hash, true); + + // XXX I am not sure if it works well every time with an empty document + // in the describe operation of an artifact. + Document description = database.describe(uuid, null, context.getMeta()); + + // Add outputmode element(s). + Node outputModes = (Node) XMLUtils.xpath( + description, + XPATH_ARTIFACT_OUTPUTMODES, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (outputModes != null) { + Document doc = ci.getOwnerDocument(); + ci.appendChild(doc.importNode(outputModes, true)); + } + + // Add state-data element(s). + Node dataNode = ci.appendChild( + ci.getOwnerDocument().createElement("art:data-items")); + + NodeList dataNodes = (NodeList) XMLUtils.xpath( + description, + XPATH_ARTIFACT_STATE_DATA, + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + if (dataNodes != null) { + Document doc = ci.getOwnerDocument(); + for (int i = 0, D = dataNodes.getLength(); i < D; i++) { + dataNode.appendChild(doc.importNode(dataNodes.item(i), true)); + } + } + + return ci; + } + + + protected void appendAttribute(Element root) { + if (attribute != null) { + Document owner = root.getOwnerDocument(); + Document attr = attribute.toXML(); + + root.appendChild(owner.importNode(attr.getFirstChild(), true)); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,612 @@ +package de.intevation.flys.collections; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifactdatabase.Backend; +import de.intevation.artifactdatabase.Backend.PersistentArtifact; +import de.intevation.artifactdatabase.DefaultArtifactCollection; +import de.intevation.artifactdatabase.state.Output; +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.exports.OutGenerator; +import de.intevation.flys.exports.OutputHelper; +import de.intevation.flys.utils.FLYSUtils; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FLYSArtifactCollection extends DefaultArtifactCollection { + /** The logger used in this class. */ + private static Logger log = Logger.getLogger(FLYSArtifactCollection.class); + + /** Constant XPath that points to the outputmodes of an artifact. */ + public static final String XPATH_ARTIFACT_OUTPUTMODES = + "/art:result/art:outputmodes"; + + public static final String XPATH_ARTIFACT_STATE_DATA = + "/art:result/art:ui/art:static/art:state/art:data"; + + public static final String XPATH_COLLECTION_ITEMS = + "/art:result/art:artifact-collection/art:collection-item"; + + public static final String XPATH_OUT_NAME = "/art:action/@art:name"; + + public static final String XPATH_OUT_TYPE = "/art:action/@art:type"; + + /** Xpath to master artifacts uuid. */ + public static final String XPATH_MASTER_UUID = + "/art:artifact-collection/art:artifact/@art:uuid"; + + public static final String XPATH_LOADED_RECOMMENDATIONS = + "/art:attribute/art:loaded-recommendations"; + + + /** + * Return description Document for this collection. + */ + @Override + public Document describe(CallContext context) { + log.debug("FLYSArtifactCollection.describe: " + identifier); + + CollectionDescriptionHelper helper = new CollectionDescriptionHelper( + getName(), identifier(), getCreationTime(), getTTL(), + context); + + ArtifactDatabase db = context.getDatabase(); + + Document oldAttrs = getAttribute(); + AttributeParser parser = new AttributeParser(oldAttrs); + + try { + String[] aUUIDs = getArtifactUUIDs(context); + + oldAttrs = removeAttributes(oldAttrs, context); + parser = new AttributeParser(oldAttrs); + + CollectionAttribute newAttr = mergeAttributes( + db, context, parser, aUUIDs); + + if (checkOutputSettings(newAttr, context)) { + saveCollectionAttribute(db, context, newAttr); + } + + helper.setAttribute(newAttr); + + if (aUUIDs != null) { + for (String uuid: aUUIDs) { + helper.addArtifact(uuid); + } + } + } + catch (ArtifactDatabaseException ade) { + log.error("Error while merging attribute documents.", ade); + + helper.setAttribute(parser.getCollectionAttribute()); + } + + return helper.toXML(); + } + + + /** + * Merge the current art:outputs nodes with the the outputs provided by the + * artifacts in the Collection. + * + * @param uuids Artifact uuids. + */ + protected CollectionAttribute mergeAttributes( + ArtifactDatabase db, + CallContext context, + AttributeParser oldParser, + String[] uuids + ) { + CollectionAttribute cAttribute = + buildOutAttributes(db, context, oldParser, uuids); + + if (cAttribute == null) { + log.warn("mergeAttributes: cAttribute == null"); + return null; + } + + cAttribute.setLoadedRecommendations( + getLoadedRecommendations(oldParser.getAttributeDocument())); + + saveCollectionAttribute(db, context, cAttribute); + + return cAttribute; + } + + + protected Document removeAttributes(Document attrs, CallContext context) { + Node outs = (Node) XMLUtils.xpath( + attrs, + "/art:attribute/art:outputs", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + NodeList nodes = (NodeList) XMLUtils.xpath( + attrs, + "/art:attribute/art:outputs/art:output", + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + if (nodes != null) { + for (int i = 0; i < nodes.getLength(); i++) { + Element e = (Element)nodes.item(i); + if(!outputExists(e.getAttribute("name"), context)) { + outs.removeChild(e); + } + } + } + return attrs; + } + + + /** + * True if current MasterArtifact has given output. + * @param name Name of the output of interest. + * @param context current context + * @return true if current master artifact has given output. + */ + protected boolean outputExists(String name, CallContext context) { + FLYSArtifact master = getMasterArtifact(context); + List<Output> outList = master.getOutputs(context); + + for (Output o : outList) { + if (name.equals(o.getName())) { + return true; + } + } + return false; + } + + /** + * @param db The ArtifactDatabase which is required to save the attribute + * into. + * @param attribute The CollectionAttribute that should be stored in the + * database. + * + * @return true, if the transaction was successful, otherwise false. + */ + protected boolean saveCollectionAttribute( + ArtifactDatabase db, + CallContext context, + CollectionAttribute attribute + ) { + log.info("Save new CollectionAttribute into database."); + + Document doc = attribute.toXML(); + + try { + // Save the merged document into database. + db.setCollectionAttribute(identifier(), context.getMeta(), doc); + + log.info("Saving CollectionAttribute was successful."); + + return true; + } + catch (ArtifactDatabaseException adb) { + log.error(adb, adb); + } + + return false; + } + + + /** + * Merge the recommendations which have already been loaded from the old + * attribute document into the new attribute document. This is necessary, + * because mergeAttributes() only merges the art:outputs nodes - all + * other nodes are skipped. + */ + protected Node getLoadedRecommendations(Document oldAttrs) { + Element loadedRecoms = (Element) XMLUtils.xpath( + oldAttrs, + XPATH_LOADED_RECOMMENDATIONS, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + return loadedRecoms; + } + + + /** + * Evaluates the Output settings. If an Output has no Settings set, the + * relevant OutGenerator is used to initialize a default Settings object. + * + * @param attribute The CollectionAttribute. + * @param cc The CallContext. + * + * @return true, if the CollectionAttribute was modified, otherwise false. + */ + protected boolean checkOutputSettings( + CollectionAttribute attribute, + CallContext cc + ) { + boolean modified = false; + + Map<String, Output> outputMap = attribute != null + ? attribute.getOutputs() + : null; + + if (outputMap == null || outputMap.isEmpty()) { + log.debug("No Output Settings check necessary."); + return modified; + } + + Set<Map.Entry<String, Output>> entries = outputMap.entrySet(); + + for (Map.Entry<String, Output> entry: entries) { + String outName = entry.getKey(); + Output output = entry.getValue(); + + if (outName.equals("sq_overview")) { + continue; + } + Settings settings = output.getSettings(); + + if (settings == null) { + log.debug("No Settings set for Output '" + outName + "'."); + output.setSettings( + createInitialOutputSettings(cc, attribute, outName)); + + modified = true; + } + } + + return modified; + } + + + /** + * This method uses the the OutGenerator for the specified Output + * <i>out</i> to create an initial Settings object. + * + * @param cc The CallContext object. + * @param attr The CollectionAttribute. + * @param out The name of the output. + * + * @return a default Settings object for the specified Output. + */ + protected Settings createInitialOutputSettings( + CallContext cc, + CollectionAttribute attr, + String out + ) { + OutGenerator outGen = FLYSContext.getOutGenerator(cc, out, null); + + if (outGen == null) { + return null; + } + + // XXX NOTE: the outGen is not able to process its generate() operation, + // because it has no OutputStream set! + outGen.init(XMLUtils.newDocument(), null, cc); + prepareMasterArtifact(outGen, cc); + + try { + Document outAttr = getAttribute(cc, attr, out); + OutputHelper helper = new OutputHelper(identifier()); + helper.doOut(outGen, out, out, outAttr, cc); + } + catch (ArtifactDatabaseException adbe) { + log.error(adbe, adbe); + } + catch (IOException ioe) { + log.error(ioe, ioe); + } + + return outGen.getSettings(); + } + + + @Override + public void out( + String type, + Document format, + OutputStream out, + CallContext context) + throws IOException + { + boolean debug = log.isDebugEnabled(); + + long reqBegin = System.currentTimeMillis(); + + if (debug) { + log.debug("FLYSArtifactCollection.out"); + } + + String name = XMLUtils.xpathString( + format, XPATH_OUT_NAME, ArtifactNamespaceContext.INSTANCE); + + String subtype = XMLUtils.xpathString( + format, XPATH_OUT_TYPE, ArtifactNamespaceContext.INSTANCE); + + if (debug) { + log.debug("-> Output name = " + name); + log.debug("-> Output type = " + type); + log.debug("-> Output subtype = " + subtype); + } + + OutGenerator generator = null; + if (type != null + && type.length() > 0 + && type.indexOf("chartinfo") > 0) + { + generator = FLYSContext.getOutGenerator(context, type, subtype); + } + else { + generator = FLYSContext.getOutGenerator(context, name, subtype); + } + + if (generator == null) { + log.error("There is no generator specified for output: " + name); + // TODO Throw an exception. + + return; + } + + Document oldAttrs = getAttribute(); + AttributeParser parser = new AttributeParser(oldAttrs); + CollectionAttribute cAttr = parser.getCollectionAttribute(); + + Output output = cAttr.getOutput(name); + Settings settings = output.getSettings(); + + generator.init(format, out, context); + generator.setSettings(settings); + generator.setCollection(this); + prepareMasterArtifact(generator, context); + + try { + Document attr = getAttribute(context, cAttr, name); + OutputHelper helper = new OutputHelper(identifier()); + if (name.equals("sq_overview")) { + helper.doOut(generator, name, subtype, format, context); + } + helper.doOut(generator, name, subtype, attr, context); + generator.generate(); + } + catch (ArtifactDatabaseException adbe) { + log.error(adbe, adbe); + } + + if (debug) { + long duration = System.currentTimeMillis() -reqBegin; + log.info("Processing out(" + name + ") took " + duration + " ms."); + } + } + + + /** + * Sets the master Artifact at the given <i>generator</i>. + * + * @param generator The generator that gets a master Artifact. + * @param cc The CallContext. + */ + protected void prepareMasterArtifact(OutGenerator generator, CallContext cc + ) { + // Get master artifact. + FLYSArtifact master = getMasterArtifact(cc); + if (master != null) { + log.debug("Set master Artifact to uuid: " + master.identifier()); + generator.setMasterArtifact(master); + } + else { + log.warn("Could not set master artifact."); + } + } + + + /** + * @return masterartifact or null if exception/not found. + */ + protected FLYSArtifact getMasterArtifact(CallContext context) + { + try { + ArtifactDatabase db = context.getDatabase(); + CallMeta callMeta = context.getMeta(); + Document document = db.getCollectionsMasterArtifact( + identifier(), callMeta); + + String masterUUID = XMLUtils.xpathString( + document, XPATH_MASTER_UUID, ArtifactNamespaceContext.INSTANCE); + FLYSArtifact masterArtifact = + (FLYSArtifact) getArtifact(masterUUID, context); + return masterArtifact; + } + catch (ArtifactDatabaseException ade) { + log.error(ade, ade); + } + return null; + } + + + /** + * Return merged output document. + * @param uuids List of artifact uuids. + */ + protected CollectionAttribute buildOutAttributes( + ArtifactDatabase db, + CallContext context, + AttributeParser aParser, + String[] uuids) + { + FLYSContext flysContext = FLYSUtils.getFlysContext(context); + StateEngine engine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + if (engine == null) { + log.error("buildOutAttributes: engine == null"); + return null; + } + + FLYSArtifact masterArtifact = getMasterArtifact(context); + + if (masterArtifact == null) { + log.debug("buildOutAttributes: masterArtifact == null"); + return null; + } + + OutputParser oParser = new OutputParser(db, context); + + if (uuids != null) { + for (String uuid: uuids) { + try { + oParser.parse(uuid); + } + catch (ArtifactDatabaseException ade) { + log.warn(ade, ade); + } + } + } + + aParser.parse(); + + AttributeWriter aWriter = new AttributeWriter( + db, + aParser.getCollectionAttribute(), + aParser.getOuts(), + aParser.getFacets(), + oParser.getOuts(), + oParser.getFacets(), + engine.getCompatibleFacets(masterArtifact.getStateHistoryIds()) + ); + return aWriter.write(); + } + + + /** + * Returns the "attribute" (part of description document) for a specific + * output type. + * + * @param context The CallContext object. + * @param cAttr The CollectionAttribute. + * @param output The name of the desired output type. + * + * @return the attribute for the desired output type. + */ + protected Document getAttribute( + CallContext context, + CollectionAttribute cAttr, + String output) + throws ArtifactDatabaseException + { + Document attr = cAttr.toXML(); + + Map<String, String> vars = new HashMap<String, String>(); + vars.put("output", output); + + Node out = (Node) XMLUtils.xpath( + attr, + "art:attribute/art:outputs/art:output[@name=$output]", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE, + vars); + + + if (out != null) { + Document o = XMLUtils.newDocument(); + + o.appendChild(o.importNode(out, true)); + + return o; + } + + return null; + } + + + /** + * This method returns the list of artifact UUIDs that this collections + * contains. + * + * @param context The CallContext that is necessary to get information about + * the ArtifactDatabase. + * + * @return a list of uuids. + */ + protected String[] getArtifactUUIDs(CallContext context) + throws ArtifactDatabaseException + { + log.debug("FLYSArtifactCollection.getArtifactUUIDs"); + + ArtifactDatabase db = context.getDatabase(); + CallMeta meta = context.getMeta(); + + Document itemList = db.listCollectionArtifacts(identifier(), meta); + NodeList items = (NodeList) XMLUtils.xpath( + itemList, + XPATH_COLLECTION_ITEMS, + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + if (items == null || items.getLength() == 0) { + log.debug("No artifacts found in this collection."); + return null; + } + + int num = items.getLength(); + + List<String> uuids = new ArrayList<String>(num); + + for (int i = 0; i < num; i++) { + String uuid = XMLUtils.xpathString( + items.item(i), + "@art:uuid", + ArtifactNamespaceContext.INSTANCE); + + if (uuid != null && uuid.trim().length() != 0) { + uuids.add(uuid); + } + } + + return uuids.toArray(new String[uuids.size()]); + } + + + /** + * Returns a concrete Artifact of this collection specified by its uuid. + * + * @param uuid The Artifact's uuid. + * @param context The CallContext. + * + * @return an Artifact. + */ + protected Artifact getArtifact(String uuid, CallContext context) + throws ArtifactDatabaseException + { + log.debug("FLYSArtifactCollection.getArtifact"); + + Backend backend = Backend.getInstance(); + PersistentArtifact persistent = backend.getArtifact(uuid); + + return persistent != null ? persistent.getArtifact() : null; + } + + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/OutputParser.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,139 @@ +package de.intevation.flys.collections; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Output; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.ManagedFacetAdapter; + + +/** + * The OutputParsers task is to pull Artifacts from database and put + * its outputs and facets into some structures. + */ +public class OutputParser { + + /** Constant XPath that points to the outputmodes of an artifact. */ + public static final String XPATH_ARTIFACT_OUTPUTMODES = + "/art:result/art:outputmodes/art:output"; + + private static Logger logger = Logger.getLogger(OutputParser.class); + + protected ArtifactDatabase db; + protected CallMeta meta; + protected CallContext context; + + /** Map outputs name to Output. */ + protected Map<String, Output> outs; + + /** Map facets name to list of Facets. */ + protected List<Facet> facets; + + + /** + * @param db Database used to fetch artifacts, outputs and facets. + */ + public OutputParser(ArtifactDatabase db, CallContext context) { + this.db = db; + this.meta = context.getMeta(); + this.context = context; + this.outs = new HashMap<String, Output>(); + this.facets = new ArrayList<Facet>(); + } + + + /** + * Gets raw artifact with given id and sorts outputs in mapping. + * Converts Facets to ManagedFacets on the way. + * @param uuid uuid of artifact to load from database. + */ + public void parse(String uuid) + throws ArtifactDatabaseException + { + logger.debug("OutputParser.parse: " + uuid); + + FLYSArtifact flys = (FLYSArtifact) db.getRawArtifact(uuid); + + List<Output> outList = flys.getOutputs(context); + + logger.debug(" has " + outList.size() + " Outputs."); + + for (Output out: outList) { + String name = out.getName(); + logger.debug("Process Output '" + name + "'"); + + Output o = outs.get(name); + int pos = 1; + + if (o == null) { + o = new DefaultOutput( + out.getName(), + out.getDescription(), + out.getMimeType(), + new ArrayList<Facet>(), + out.getType()); + outs.put(name, o); + } + else { + logger.debug("OutputParser.parse: Use 'old' Output"); + pos = o.getFacets().size() + 1; + } + + List<Facet> mfacets = facet2ManagedFacet(uuid, out.getFacets(), pos); + o.addFacets(mfacets); + this.facets.addAll(mfacets); + } + } + + + /** + * Access mapping of Outputname to Output. + */ + public Map<String, Output> getOuts() { + return outs; + } + + + /** + * Access all facets. + */ + public List<Facet> getFacets() { + return this.facets; + } + + + /** + * Creates a list of ManagedFacets from list of Facets. + * @param pos Position of first facet (for each other the positions + * will be increased). + */ + protected List<Facet> facet2ManagedFacet( + String uuid, + List<Facet> old, + int pos) + { + List<Facet> newFacets = new ArrayList<Facet>(old.size()); + + logger.debug("There are " + old.size() + " Facets for this Output."); + + for (Facet f: old) { + newFacets.add(new ManagedFacetAdapter(f, uuid, pos++, 1, 1)); + } + + return newFacets; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ATExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,118 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.IOException; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.WQ; +import de.intevation.flys.collections.FLYSArtifactCollection; + +import de.intevation.flys.utils.FLYSUtils; + + +public class ATExporter +implements OutGenerator +{ + private static Logger logger = Logger.getLogger(ATExporter.class); + + public static final String DEFAULT_ENCODING = "UTF-8"; + + protected WQ data; + protected CallContext context; + protected OutputStream out; + protected FLYSArtifact master; + + protected FLYSArtifactCollection collection; + + + public ATExporter() { + } + + @Override + public void init(Document request, OutputStream out, CallContext context) { + this.context = context; + this.out = out; + } + + + @Override + public void setMasterArtifact(Artifact master) { + this.master = (FLYSArtifact) master; + } + + @Override + public void setCollection(FLYSArtifactCollection collection) { + this.collection = collection; + } + + @Override + public void doOut( + ArtifactAndFacet artifactf, + Document attr, + boolean visible + ) { + data = (WQ)artifactf.getData(context); + } + + @Override + public void generate() throws IOException { + + if (data == null) { + logger.debug("no W/Q data"); + return; + } + + ATWriter at; + try { + at = new ATWriter(data); + } + catch (IllegalArgumentException iae) { + logger.error("creating ATWriter failed", iae); + throw new IOException(iae); + } + + String river = FLYSUtils.getRiver(master).getName(); + double[] kms = FLYSUtils.getLocations(master); + + at.write( + new OutputStreamWriter(out, DEFAULT_ENCODING), + context.getMeta(), + river, + kms[0]); + } + + + /** + * Returns an instance of <i>EmptySettings</i> currently! + * + * @return an instance of <i>EmptySettings</i>. + */ + @Override + public Settings getSettings() { + return new EmptySettings(); + } + + + /** + * This method is not implemented! + * + * @param settings A settings object. + */ + @Override + public void setSettings(Settings settings) { + // do nothing here + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ATWriter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,166 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.Writer; +import java.io.PrintWriter; + +import java.util.Locale; + +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.WQ; +import de.intevation.flys.artifacts.resources.Resources; + +import org.apache.commons.math.analysis.UnivariateRealFunction; + +import org.apache.commons.math.analysis.interpolation.SplineInterpolator; +import org.apache.commons.math.analysis.interpolation.LinearInterpolator; + +import org.apache.commons.math.analysis.polynomials.PolynomialFunction; + +import org.apache.commons.math.FunctionEvaluationException; + +import org.apache.log4j.Logger; + +public class ATWriter +{ + private static Logger logger = Logger.getLogger(ATWriter.class); + + public static final int COLUMNS = 10; + + public static final String I18N_AT_HEADER = + "export.discharge.curve.at.header"; + + public static final String EMPTY = " "; + + protected double minW; + protected double maxW; + protected double minQ; + protected double maxQ; + + protected UnivariateRealFunction qFunc; + + public ATWriter() { + } + + public ATWriter(WQ wq) throws IllegalArgumentException { + + int [] bounds = wq.longestIncreasingWRangeIndices(); + + if (logger.isDebugEnabled()) { + logger.debug("exporting w between indices " + + bounds[0] + " and " + bounds[1] + " (" + + wq.getW(bounds[0]) + ", " + wq.getW(bounds[1])); + } + + if (bounds[1]-bounds[0] < 1) { // Only first w can be written out. + minW = maxW = wq.getW(bounds[0]); + minQ = maxQ = wq.getQ(bounds[0]); + // constant function + qFunc = new PolynomialFunction(new double [] { minQ }); + return; + } + + double [] ws = new double[bounds[1]-bounds[0]]; + double [] qs = new double[ws.length]; + + for (int i = 0; i < ws.length; ++i) { + int idx = bounds[0]+i; + ws[i] = wq.getW(idx); + qs[i] = wq.getQ(idx); + } + + qFunc = ws.length < 3 + ? new LinearInterpolator().interpolate(ws, qs) + : new SplineInterpolator().interpolate(ws, qs); + + minW = wq.getW(bounds[0]); + maxW = wq.getW(bounds[1]); + minQ = wq.getQ(bounds[0]); + maxQ = wq.getQ(bounds[1]); + } + + public double getQ(double w) { + + try { + return qFunc.value(w); + } + catch (FunctionEvaluationException aode) { + // should not happen + logger.warn("spline interpolation failed", aode); + return w <= minW ? minQ : maxQ; + } + } + + public static void printQ(PrintWriter out, double q) { + String format; + if (q < 1d) format = " % 8.3f"; + else if (q < 10d) format = " % 8.2f"; + else if (q < 100d) format = " % 8.1f"; + else { + format = " % 8.0f"; + if (q > 1000d) q = Math.rint(q/10d)*10d; + } + out.printf(Locale.US, format, q); + } + + + protected static void printHeader( + PrintWriter out, + CallMeta callMeta, + String river, + double km + ) { + out.println(Resources.getMsg( + callMeta, + I18N_AT_HEADER, + I18N_AT_HEADER, + new Object[] { river, km } )); + } + + + public void write(Writer writer, CallMeta meta, String river, double km) + throws IOException + { + PrintWriter out = new PrintWriter(writer); + + // a header is required, because the desktop version of FLYS will skip + // the first row. + printHeader(out, meta, river, km); + + double rest = (minW * 100.0) % 10.0; + + double startW = Math.rint((minW - rest*0.01)*10.0)*0.1; + + if (logger.isDebugEnabled()) { + logger.debug("startW: " + startW); + logger.debug("rest: " + rest); + } + + int col = 0; + for (double w = startW; w <= maxW; w += 0.01) { + if (col == 0) { + out.printf(Locale.US, "%8d", (int)Math.round(w*100.0)); + } + + if (w < minW) { + out.print(EMPTY); + } + else { + printQ(out, getQ(w)); + } + + if (++col >= COLUMNS) { + out.println(); + col = 0; + } + } + + if (col > 0) { + out.println(); + } + + out.flush(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/AbstractExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,318 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import java.text.NumberFormat; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.collections.FLYSArtifactCollection; + +import de.intevation.flys.utils.Formatter; + + +/** + * An abstract exporter that implements some basic methods for exporting data of + * artifacts. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class AbstractExporter implements OutGenerator { + + /** The logger used in this exporter.*/ + private static Logger logger = Logger.getLogger(AbstractExporter.class); + + /* XXX: Why does AbstractExporter do not implement FacetTypes? */ + public static String FIX_PARAMETERS = "fix_parameters"; + + /** The name of the CSV facet which triggers the CSV creation. */ + public static final String FACET_CSV = "csv"; + + /** The name of the PDF facet which triggers the PDF creation. */ + public static final String FACET_PDF = "pdf"; + + /** The default charset for the CSV export. */ + public static final String DEFAULT_CSV_CHARSET = "UTF-8"; + + /** The default separator for the CSV export. */ + public static final char DEFAULT_CSV_SEPARATOR = ','; + + /** XPath that points to the desired export facet. */ + public static final String XPATH_FACET = "/art:action/@art:type"; + + /** The document of the incoming out() request. */ + protected Document request; + + /** The output stream where the data should be written to. */ + protected OutputStream out; + + /** The CallContext object. */ + protected CallContext context; + + /** The selected facet. */ + protected String facet; + + /** The collection.*/ + protected FLYSArtifactCollection collection; + + /** The master artifact. */ + protected Artifact master; + + + /** + * Concrete subclasses need to use this method to write their special data + * objects into the CSV document. + * + * @param writer The CSVWriter. + */ + protected abstract void writeCSVData(CSVWriter writer) throws IOException; + + + /** + * Concrete subclasses need to use this method to write their special data + * objects into the PDF document. + */ + protected abstract void writePDF(OutputStream out); + + + /** + * This method enables concrete subclasses to collected its own special + * data. + * + * @param data The artifact that stores the data that has to be + * exported. + */ + protected abstract void addData(Object data); + + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("AbstractExporter.init"); + + this.request = request; + this.out = out; + this.context = context; + } + + + @Override + public void setMasterArtifact(Artifact master) { + this.master = master; + } + + + @Override + public void setCollection(FLYSArtifactCollection collection) { + this.collection = collection; + } + + + /** + * This doOut() just collects the data of multiple artifacts. Therefore, it + * makes use of the addData() method which enables concrete subclasses to + * store its data on its own. The real output creation takes place in the + * concrete generate() methods. + * + * @param artifactFacet The artifact and facet. + * The facet to add - NOTE: the facet needs to fit to the first + * facet inserted into this exporter. Otherwise this artifact/facet is + * skipped. + * @param attr The attr document. + */ + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("AbstractExporter.doOut: " + name); + + if (!isFacetValid(name)) { + logger.warn("Facet '" + name + "' not valid. No output created!"); + return; + } + + addData(artifactFacet.getData(context)); + } + + + /** + * Generates an export based on a specified facet. + */ + @Override + public void generate() + throws IOException + { + logger.debug("AbstractExporter.generate"); + + if (facet == null) { + throw new IOException("invalid (null) facet for exporter"); + } + + if (facet.equals(FACET_CSV)) { + generateCSV(); + } + else if (facet.equals(FACET_PDF)) { + generatePDF(); + } + else { + throw new IOException( + "invalid facet for exporter: '" + facet + "'"); + } + } + + + /** + * Determines if the desired facet is valid for this exporter. If no facet + * is currently set, <i>facet</i> is set. + * + * @param facet The desired facet. + * + * @return true, if <i>facet</i> is valid, otherwise false. + */ + protected boolean isFacetValid(String facet) { + logger.debug("AbstractExporter.isFacetValid : " + facet + " (" + getFacet() + ")" ); + + String thisFacet = getFacet(); + + if (thisFacet == null || thisFacet.length() == 0) { + return false; + } + else if (facet == null || facet.length() == 0) { + return false; + } + else { + return thisFacet.equals(facet); + } + } + + + /** + * Returns the name of the desired facet. + * + * @return the name of the desired facet. + */ + protected String getFacet() { + if (facet == null) { + facet = getFacetFromRequest(); + } + + return facet; + } + + + /** + * Extracts the name of the requested facet from request document. + * + * @return the name of the requested facet. + */ + protected String getFacetFromRequest() { + return XMLUtils.xpathString( + request, XPATH_FACET, ArtifactNamespaceContext.INSTANCE); + } + + + protected String msg(String key, String def) { + return Resources.getMsg(context.getMeta(), key, def); + } + + + /** + * This method starts CSV creation. It makes use of writeCSVData() which has + * to be implemented by concrete subclasses. + */ + protected void generateCSV() + throws IOException + { + logger.info("AbstractExporter.generateCSV"); + + CSVWriter writer = new CSVWriter( + new OutputStreamWriter( + out, + DEFAULT_CSV_CHARSET), + DEFAULT_CSV_SEPARATOR); + + writeCSVData(writer); + + writer.close(); + } + + + /** + * This method starts PDF creation. + */ + protected void generatePDF() + throws IOException + { + logger.info("AbstractExporter.generatePDF"); + writePDF(this.out); + } + + + /** + * Returns an instance of <i>EmptySettings</i> currently! + * + * @return an instance of <i>EmptySettings</i>. + */ + public Settings getSettings() { + return new EmptySettings(); + } + + + /** + * This method is not implemented. Override it in subclasses if those need a + * <i>Settings</i> object. + */ + public void setSettings(Settings settings) { + // do nothing + } + + + /** + * Returns the number formatter for kilometer values. + * + * @return the number formatter for kilometer values. + */ + protected NumberFormat getKmFormatter() { + return Formatter.getWaterlevelKM(context); + } + + + /** + * Returns the number formatter for W values. + * + * @return the number formatter for W values. + */ + protected NumberFormat getWFormatter() { + return Formatter.getWaterlevelW(context); + } + + + /** + * Returns the number formatter for Q values. + * + * @return the number formatter for Q values. + */ + protected NumberFormat getQFormatter() { + return Formatter.getWaterlevelQ(context); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/AxisSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,106 @@ +package de.intevation.flys.exports; + + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.state.Attribute; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class AxisSection extends TypeSection { + + public static final String IDENTIFIER_ATTR = "id"; + public static final String LABEL_ATTR = "label"; + public static final String FONTSIZE_ATTR = "font-size"; + public static final String FIXATION_ATTR = "fixation"; + public static final String UPPERRANGE_ATTR = "upper"; + public static final String LOWERRANGE_ATTR = "lower"; + + + public AxisSection() { + super("axis"); + } + + + public void setIdentifier(String identifier) { + setStringValue(IDENTIFIER_ATTR, identifier); + } + + + public String getIdentifier() { + return getStringValue(IDENTIFIER_ATTR); + } + + + public void setLabel(String label) { + setStringValue(LABEL_ATTR, label); + } + + + public String getLabel() { + return getStringValue(LABEL_ATTR); + } + + + public void setFontSize(int fontSize) { + if (fontSize <= 0) { + return; + } + + setIntegerValue(FONTSIZE_ATTR, fontSize); + } + + + public Integer getFontSize() { + return getIntegerValue(FONTSIZE_ATTR); + } + + + public void setFixed(boolean fixed) { + setBooleanValue(FIXATION_ATTR, fixed); + } + + + public Boolean isFixed() { + return getBooleanValue(FIXATION_ATTR); + } + + + public void setUpperRange(double upperRange) { + setDoubleValue(UPPERRANGE_ATTR, upperRange); + } + + + public Double getUpperRange() { + return getDoubleValue(UPPERRANGE_ATTR); + } + + + public void setLowerRange(double lowerRange) { + setDoubleValue(LOWERRANGE_ATTR, lowerRange); + } + + + public Double getLowerRange() { + return getDoubleValue(LOWERRANGE_ATTR); + } + + + @Override + public void toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + Element axis = owner.createElement("axis"); + + parent.appendChild(axis); + + for (String key: getKeys()) { + Attribute attr = getAttribute(key); + attr.toXML(axis); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/BooleanAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,37 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BooleanAttribute extends VisibleAttribute { + + + public BooleanAttribute(String name, boolean value, boolean visible) { + super(name, value, visible); + } + + + /** + * Calls VisibleAttribute.toXML() and appends afterwards an attribute + * <i>type</i> with value <i>boolean</i>. + * + * @param parent The parent Node. + * + * @return the new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("type", "boolean"); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartArea.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,57 @@ +package de.intevation.flys.exports; + +import org.jfree.chart.axis.ValueAxis; + +import org.jfree.data.Range; + +/** Two Ranges that span a rectangular area. */ +public class ChartArea { + protected Range xRange; + protected Range yRange; + + public ChartArea(Range rangeX, Range rangeY) { + this.xRange = rangeX; + this.yRange = rangeY; + } + + public ChartArea(ValueAxis axisX, ValueAxis axisY) { + this.xRange = axisX.getRange(); + this.yRange = axisY.getRange(); + } + + public double ofLeft(double percent) { + return xRange.getLowerBound() + + xRange.getLength() * percent; + } + + public double ofRight(double percent) { + return xRange.getUpperBound() + - xRange.getLength() * percent; + } + + public double ofGround(double percent) { + return yRange.getLowerBound() + + yRange.getLength() * percent; + } + + public double atTop() { + return yRange.getUpperBound(); + } + + public double atGround() { + return yRange.getLowerBound(); + } + + public double atRight() { + return xRange.getUpperBound(); + } + + public double atLeft() { + return xRange.getLowerBound(); + } + + public double above(double percent, double base) { + return base + yRange.getLength() * percent; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2011 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ +package de.intevation.flys.exports; + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.PageSize; +import com.lowagie.text.Rectangle; + +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; + +import java.awt.Graphics2D; +import java.awt.Transparency; + +import java.awt.geom.Rectangle2D.Double; + +import java.awt.geom.Rectangle2D; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import org.jfree.chart.ChartRenderingInfo; + +import javax.imageio.ImageIO; + +import au.com.bytecode.opencsv.CSVWriter; + +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; + +import org.apache.log4j.Logger; + +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYDataset; + +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + + +/** + * This class is a helper class which supports some methods to export charts + * into specific formats. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChartExportHelper { + + public static final String FORMAT_PNG = "png"; + + public static final String FORMAT_PDF = "pdf"; + + public static final String FORMAT_SVG = "svg"; + + public static final String FORMAT_CSV = "csv"; + + /** + * Constant field to define A4 as default page size. + */ + public static final String DEFAULT_PAGE_SIZE = "A4"; + + /** + * Constant field to define UTF-8 as default encoding. + */ + public static final String DEFAULT_ENCODING = "UTF-8"; + + /** The default separator for the CSV export. */ + public static final char DEFAULT_CSV_SEPARATOR = ','; + + + /** + * Logger used for logging with log4j. + */ + private static Logger log = Logger.getLogger(ChartExportHelper.class); + + + /** + * A method to export a <code>JFreeChart</code> as image to an + * <code>OutputStream</code> with a given format, width and height. + * + * @param out OutputStream + * @param chart JFreeChart object to be exported. + * @param cc context, in which e.g. size is stored. + * + * @throws IOException if writing image to OutputStream failed. + */ + public static void exportImage( + OutputStream out, + JFreeChart chart, + CallContext cc + ) + throws IOException + { + log.info("export chart as png"); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + String format = (String) cc.getContextValue("chart.image.format"); + + int[] size = getSize(cc); + + ImageIO.write( + chart.createBufferedImage( + size[0], size[1], Transparency.BITMASK, info + ), + format, + out + ); + } + + + /** + * A method to export a <code>JFreeChart</code> as SVG to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart to be exported + * @param context The CallContext object that contains extra chart + * parameters. + */ + public static void exportSVG( + OutputStream out, + JFreeChart chart, + CallContext context + ) { + String encoding = (String) context.getContextValue("chart.encoding"); + + log.info("export chart as svg"); + + if (encoding == null) + encoding = DEFAULT_ENCODING; + + org.w3c.dom.Document document = XMLUtils.newDocument(); + SVGGraphics2D graphics = new SVGGraphics2D(document); + + int[] size = getSize(context); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,size[0],size[1]), info); + + try { + graphics.stream(new OutputStreamWriter(out, encoding)); + } + catch (SVGGraphics2DIOException svge) { + log.error("Error while writing svg export to output stream.", svge); + } + catch (UnsupportedEncodingException uee) { + log.error("Unsupported encoding: " + encoding, uee); + } + } + + + /** + * A method to export a <code>JFreeChart</code> as PDF to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart + */ + public static void exportPDF( + OutputStream out, + JFreeChart chart, + CallContext cc + ) { + log.info("export chart as pdf."); + + String pageFormat = (String) cc.getContextValue("chart.page.format"); + + if (pageFormat == null) + pageFormat = DEFAULT_PAGE_SIZE; + + // Max size of the chart. + Rectangle page = PageSize.getRectangle(pageFormat); + float pageWidth = page.getWidth(); + float pageHeight = page.getHeight(); + + // The chart width. + int[] size = getSize(cc); + + boolean landscape = size[0] > size[1]; + + float width = 0; + float height = 0; + if (landscape) { + width = pageHeight; + height = pageWidth; + } + else { + width = pageWidth; + height = pageHeight; + } + + float marginLeft = (Float) cc.getContextValue( + "chart.marginLeft"); + + float marginRight = (Float) cc.getContextValue( + "chart.marginRight"); + + float marginTop = (Float) cc.getContextValue( + "chart.marginTop"); + + float marginBottom = (Float) cc.getContextValue( + "chart.marginBottom"); + + float spaceX = width - marginLeft - marginRight; + if (size[0] > spaceX) { + log.warn("Width of the chart is too big for pdf -> resize it now."); + double ratio = ((double)spaceX) / size[0]; + size[0] *= ratio; + size[1] *= ratio; + log.debug("Resized chart to " + size[0] + "x" + size[1]); + } + + float spaceY = height - marginTop - marginBottom; + if (size[1] > spaceY) { + log.warn("Height of the chart is too big for pdf -> resize it now."); + double ratio = ((double)spaceY) / size[1]; + size[0] *= ratio; + size[1] *= ratio; + log.debug("Resized chart to " + size[0] + "x" + size[1]); + } + + Document document = null; + if (landscape) { + document = new Document(page.rotate()); + log.debug("Create landscape pdf."); + } + else + document = new Document(page); + + try { + PdfWriter writer = PdfWriter.getInstance(document, out); + + document.addSubject(chart.getTitle().getText()); + document.addCreationDate(); + document.open(); + + PdfContentByte content = writer.getDirectContent(); + + PdfTemplate template = content.createTemplate(width, height); + Graphics2D graphics = template.createGraphics(width, height); + + double[] origin = getCenteredAnchor( + marginLeft, marginRight, marginBottom, marginTop, + width, height, + size[0], size[1]); + + Rectangle2D area = new Rectangle2D.Double( + origin[0], origin[1], size[0], size[1]); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + chart.draw(graphics, area, info); + graphics.dispose(); + content.addTemplate(template, 0f, 0f); + } + catch (DocumentException de) { + log.error("Error while exporting chart to pdf.", de); + } + finally { + document.close(); + } + } + + + /** + * A method to export a CSV file to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart containing the data. + * @param context The CallContext object that contains extra parameters. + */ + public static void exportCSV( + OutputStream out, + JFreeChart chart, + CallContext context) + { + log.debug("export chart as CSV"); + CSVWriter writer = null; + try { + writer = new CSVWriter( + new OutputStreamWriter( + out, + DEFAULT_ENCODING), + DEFAULT_CSV_SEPARATOR); + } + catch(UnsupportedEncodingException uee) { + log.warn("Wrong encoding for CSV export."); + return; + } + XYPlot plot = chart.getXYPlot(); + int count = plot.getDatasetCount(); + for (int i = 0; i < count; i++) { + XYDataset data = plot.getDataset(i); + int scount = data.getSeriesCount(); + for (int j = 0; j < scount; j++) { + Comparable seriesKey = data.getSeriesKey(j); + log.debug("series key: " + seriesKey.toString()); + writeCSVHeader(writer, seriesKey.toString()); + writeCSVData(writer, data); + } + } + try { + writer.close(); + } + catch(IOException ioe) { + log.error("Writing CSV export failed!"); + } + } + + + protected static void writeCSVHeader(CSVWriter writer, String key) { + writer.writeNext(new String[] {"#"}); + writer.writeNext(new String[] {"# " + key}); + writer.writeNext(new String[] {"#"}); + writer.writeNext(new String[] {"X", "Y"}); + } + + + protected static void writeCSVData(CSVWriter writer, XYDataset data) { + int series = data.getSeriesCount(); + for (int i = 0; i < series; i++) { + int items = data.getItemCount(i); + for (int j = 0; j < items; j++) { + log.debug("write data: " + data.getX(i, j) + ", " + data.getY(i, j)); + writer.writeNext(new String[] { + data.getX(i, j).toString(), + data.getY(i, j).toString()}); + } + } + } + + + public static int[] getSize(CallContext cc) { + int[] size = new int[2]; + + size[0] = (Integer) cc.getContextValue("chart.width"); + size[1] = (Integer) cc.getContextValue("chart.height"); + + return size; + } + + + /** + * This method returns the anchor of the chart so that the chart is centered + * according to the given parameters. + * + * @param mLeft Left margin + * @param mRight Right margin + * @param mBottom Bottom margin + * @param mTop Top margin + * @param width The complete width of the drawing area. + * @param height The complete height of the drawing area. + * @param chartWidth The width of the chart. + * @param chartHeight The height of the chart. + * + * @return an array that contains the anchor for a chart with the given + * parameters. The first value is the x point, the second value is the y + * point. + */ + public static double[] getCenteredAnchor( + double mLeft, double mRight, double mBottom, double mTop, + double width, double height, + double chartWidth, double chartHeight + ) { + if (log.isDebugEnabled()) { + log.debug("Calculate centered origin..."); + log.debug("-> PDF width : " + width); + log.debug("-> PDF height : " + height); + log.debug("-> Chart width : " + chartWidth); + log.debug("-> Chart height : " + chartHeight); + log.debug("-> margin left : " + mLeft); + log.debug("-> margin right : " + mRight); + log.debug("-> margin bottom: " + mBottom); + log.debug("-> margin top : " + mTop); + } + + double[] origin = new double[2]; + + double centerX = width / 2; + double centerY = height / 2; + + origin[0] = centerX - chartWidth / 2; + origin[1] = centerY - chartHeight / 2; + + origin[0] = origin[0] >= mLeft ? origin[0] : mLeft; + origin[1] = origin[1] >= mTop ? origin[1] : mTop; + + if (log.isDebugEnabled()) { + log.debug("==> centered left origin: " + origin[0]); + log.debug("==> centered top origin: " + origin[1]); + } + + return origin; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1871 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.PreferredLocale; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.collections.FLYSArtifactCollection; +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.jfree.DoubleBounds; +import de.intevation.flys.jfree.EnhancedLineAndShapeRenderer; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StableXYDifferenceRenderer; +import de.intevation.flys.jfree.StickyAxisAnnotation; +import de.intevation.flys.jfree.Style; +import de.intevation.flys.jfree.StyledAreaSeriesCollection; +import de.intevation.flys.jfree.StyledSeries; +import de.intevation.flys.model.River; +import de.intevation.flys.themes.LineStyle; +import de.intevation.flys.themes.TextStyle; +import de.intevation.flys.themes.ThemeAccess; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.ThemeUtil; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Paint; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYLineAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.chart.title.TextTitle; +import org.jfree.data.Range; +import org.jfree.data.general.Series; +import org.jfree.data.xy.XYDataset; +import org.jfree.ui.RectangleInsets; +import org.jfree.ui.TextAnchor; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.flys.utils.Formatter; + +/** + * The base class for chart creation. It should provide some basic things that + * equal in all chart types. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class ChartGenerator implements OutGenerator { + + private static Logger logger = Logger.getLogger(ChartGenerator.class); + + public static final int DEFAULT_CHART_WIDTH = 600; + public static final int DEFAULT_CHART_HEIGHT = 400; + public static final String DEFAULT_CHART_FORMAT = "png"; + public static final Color DEFAULT_GRID_COLOR = Color.GRAY; + public static final float DEFAULT_GRID_LINE_WIDTH = 0.3f; + public static final int DEFAULT_FONT_SIZE = 12; + public static final String DEFAULT_FONT_NAME = "Tahoma"; + + protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f; + + public static final String XPATH_CHART_SIZE = + "/art:action/art:attributes/art:size"; + + public static final String XPATH_CHART_FORMAT = + "/art:action/art:attributes/art:format/@art:value"; + + public static final String XPATH_CHART_X_RANGE = + "/art:action/art:attributes/art:xrange"; + + public static final String XPATH_CHART_Y_RANGE = + "/art:action/art:attributes/art:yrange"; + + + /** The document of the incoming out() request.*/ + protected Document request; + + /** The output stream where the data should be written to.*/ + protected OutputStream out; + + /** The CallContext object.*/ + protected CallContext context; + + protected FLYSArtifactCollection collection; + + /** The artifact that is used to decorate the chart with meta information.*/ + protected Artifact master; + + /** The settings that should be used during output creation.*/ + protected Settings settings; + + /** Map of datasets ("index"). */ + protected SortedMap<Integer, AxisDataset> datasets; + + /** List of annotations to insert in plot. */ + protected List<FLYSAnnotation> annotations = new ArrayList<FLYSAnnotation>(); + + /** + * A mini interface that allows to walk over the YAXIS enums defined in + * subclasses. + */ + public interface YAxisWalker { + + int length(); + + String getId(int idx); + } // end of YAxisWalker interface + + + + public interface AxisDataset { + + void addDataset(XYDataset dataset); + + XYDataset[] getDatasets(); + + boolean isEmpty(); + + void setRange(Range range); + + Range getRange(); + + boolean isArea(XYDataset dataset); + + void setPlotAxisIndex(int idx); + + int getPlotAxisIndex(); + + } // end of AxisDataset interface + + + + /** + * Default constructor that initializes internal data structures. + */ + public ChartGenerator() { + datasets = new TreeMap<Integer, AxisDataset>(); + } + + + /** + * Adds annotations to list. The given annotation will be visible. + */ + public void addAnnotations(FLYSAnnotation annotation) { + annotations.add(annotation); + } + + /** + * Add a text and a line annotation. + * @param area convenience to determine positions in plot. + * @param theme (optional) theme document + */ + protected void addStickyAnnotation( + StickyAxisAnnotation annotation, + XYPlot plot, + ChartArea area, + LineStyle lineStyle, + TextStyle textStyle, + Document theme + ) { + // OPTIMIZE pre-calculate area-related values + final float TEXT_OFF = 0.03f; + + XYLineAnnotation lineAnnotation = null; + XYTextAnnotation textAnnotation = null; + + int rendererIndex = 0; + + if (annotation.atX()) { + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF)); + // OPTIMIZE externalize the calculation involving PI. + //textAnnotation.setRotationAngle(270f*Math.PI/180f); + lineAnnotation = createGroundStickAnnotation( + area, annotation.getPos(), lineStyle); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + } + else { + // Do the more complicated case where we stick to the Y-Axis. + // There is one nasty case (duration curves, where annotations + // might stick to the second y-axis). + // FIXME: Remove dependency to XYChartGenerator here + AxisDataset dataset = getAxisDataset( + new Integer(annotation.getAxisSymbol())); + if (dataset == null) { + logger.warn("Annotation should stick to unfindable y-axis: " + + annotation.getAxisSymbol()); + rendererIndex = 0; + } + else { + rendererIndex = dataset.getPlotAxisIndex(); + } + + // Stick to the "right" (opposed to left) Y-Axis. + if (rendererIndex != 0) { + // OPTIMIZE: Pass a different area to this function, + // do the adding to renderer outside (let this + // function return the annotations). + // Note that this path is travelled rarely. + ChartArea area2 = new ChartArea(plot.getDomainAxis(), plot.getRangeAxis(rendererIndex)); + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), area2.ofRight(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT); + lineAnnotation = createRightStickAnnotation( + area2, annotation.getPos(), lineStyle); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (ThemeUtil.parseShowVerticalLine(theme)) { + XYLineAnnotation hitLineAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.X_AXIS, + annotation.getHitPoint(), annotation.getPos(),// annotation.getHitPoint(), + area2, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + if (ThemeUtil.parseShowHorizontalLine(theme)) { + XYLineAnnotation lineBackAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.Y_AXIS2, + annotation.getPos(), annotation.getHitPoint(), + area2, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + } + } + else { // Stick to the left y-axis. + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (ThemeUtil.parseShowHorizontalLine(theme)) { + XYLineAnnotation hitLineAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.Y_AXIS, + annotation.getPos(), annotation.getHitPoint(), + area, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + if (ThemeUtil.parseShowVerticalLine(theme)) { + XYLineAnnotation lineBackAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.X_AXIS, + annotation.getHitPoint(), annotation.getPos(), + area, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + } + } + } + + // Style the text. + if (textStyle != null) { + textStyle.apply(textAnnotation); + } + + // Add the Annotations to renderer. + plot.getRenderer(rendererIndex).addAnnotation(textAnnotation, + org.jfree.ui.Layer.FOREGROUND); + plot.getRenderer(rendererIndex).addAnnotation(lineAnnotation, + org.jfree.ui.Layer.FOREGROUND); + } + + /** + * Create annotation that sticks to "ground" (X) axis. + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + protected static XYLineAnnotation createGroundStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + pos, area.atGround(), + pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET), + new BasicStroke(lineStyle.getWidth()),lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + pos, area.atGround(), + pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET)); + } + } + + + /** + * Create annotation that sticks to the second Y axis ("right"). + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + protected static XYLineAnnotation createRightStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos, + area.atRight(), pos, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + area.atRight(), pos, + area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos); + } + } + + + /** + * Create annotation that sticks to the first Y axis ("left"). + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + protected static XYLineAnnotation createLeftStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + area.atLeft(), pos, + area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + area.atLeft(), pos, + area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos); + } + } + + + /** + * Create a line from a axis to a given point. + * @param axis The "simple" axis. + * @param fromD1 from-location in first dimension. + * @param toD2 to-location in second dimension. + * @param area helper to calculate offsets. + * @param lineStyle optional line style. + */ + protected static XYLineAnnotation createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis axis, float fromD1, float toD2, + ChartArea area, LineStyle lineStyle + ) { + double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d; + switch(axis) { + case X_AXIS: + anchorX1 = fromD1; + anchorX2 = fromD1; + anchorY1 = area.atGround(); + anchorY2 = toD2; + break; + case Y_AXIS: + anchorX1 = area.atLeft(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + case Y_AXIS2: + anchorX1 = area.atRight(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + } + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + anchorX1, anchorY1, + anchorX2, anchorY2, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + anchorX1, anchorY1, + anchorX2, anchorY2); + } + } + + /** + * Add the annotations (Sticky, Text and hyk zones) stored + * in the annotations field. + * @param plot Plot to add annotations to. + */ + protected void addAnnotationsToRenderer(XYPlot plot) { + logger.debug("addAnnotationsToRenderer"); + + if (annotations == null || annotations.isEmpty()) { + logger.debug("addAnnotationsToRenderer: no annotations."); + return; + } + + // OPTMIMIZE: Pre-calculate positions + ChartArea area = new ChartArea( + plot.getDomainAxis(0).getRange(), + plot.getRangeAxis().getRange()); + + // Walk over all Annotation sets. + for (FLYSAnnotation fa: annotations) { + + // Access text styling, if any. + Document theme = fa.getTheme(); + TextStyle textStyle = null; + LineStyle lineStyle = null; + + // Get Themeing information and add legend item. + if (theme != null) { + ThemeAccess themeAccess = new ThemeAccess(theme); + textStyle = themeAccess.parseTextStyle(); + lineStyle = themeAccess.parseLineStyle(); + if (fa.getLabel() != null) { + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + lic.add(createLegendItem(theme, fa.getLabel())); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } + else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // The 'Sticky' Annotations (at axis, with line and text). + for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) { + addStickyAnnotation( + sta, plot, area, lineStyle, textStyle, theme); + } + + // Other Text Annotations (e.g. labels of (manual) points). + for (XYTextAnnotation ta: fa.getTextAnnotations()) { + // Style the text. + if (textStyle != null) { + textStyle.apply(ta); + } + ta.setY(area.above(0.05d, ta.getY())); + plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); + } + } + } + + + /** + * This method needs to be implemented by concrete subclasses to create new + * instances of JFreeChart. + * + * @return a new instance of a JFreeChart. + */ + public abstract JFreeChart generateChart(); + + + @Override + public abstract void doOut( + ArtifactAndFacet bundle, + Document attr, + boolean visible); + + + protected abstract YAxisWalker getYAxisWalker(); + + + protected abstract Series getSeriesOf(XYDataset dataset, int idx); + + /** + * Returns the default title of a chart. + * + * @return the default title of a chart. + */ + protected abstract String getDefaultChartTitle(); + + + /** + * Returns the default X-Axis label of a chart. + * + * @return the default X-Axis label of a chart. + */ + protected abstract String getDefaultXAxisLabel(); + + + /** + * This method is called to retrieve the default label for an Y axis at + * position <i>pos</i>. + * + * @param pos The position of an Y axis. + * + * @return the default Y axis label at position <i>pos</i>. + */ + protected abstract String getDefaultYAxisLabel(int pos); + + + /** + * This method is used to create new AxisDataset instances which may differ + * in concrete subclasses. + * + * @param idx The index of an axis. + */ + protected abstract AxisDataset createAxisDataset(int idx); + + + /** + * Combines the ranges of the X axis at index <i>idx</i>. + * + * @param bounds A new Bounds. + * @param idx The index of the X axis that should be comined with + * <i>range</i>. + */ + protected abstract void combineXBounds(Bounds bounds, int idx); + + + /** + * Combines the ranges of the Y axis at index <i>idx</i>. + * + * @param bounds A new Bounds. + * @param index The index of the Y axis that should be comined with. + * <i>range</i>. + */ + protected abstract void combineYBounds(Bounds bounds, int index); + + + /** + * This method is used to determine the ranges for axes at a given index. + * + * @param index The index of the axes at the plot. + * + * @return a Range[] with [xrange, yrange]; + */ + public abstract Range[] getRangesForAxis(int index); + + public abstract Bounds getXBounds(int axis); + + protected abstract void setXBounds(int axis, Bounds bounds); + + public abstract Bounds getYBounds(int axis); + + protected abstract void setYBounds(int axis, Bounds bounds); + + + /** + * This method retrieves the chart subtitle by calling getChartSubtitle() + * and adds it as TextTitle to the chart. + * The default implementation of getChartSubtitle() returns the same + * as getDefaultChartSubtitle() which must be implemented by derived + * classes. If you want to add multiple subtitles to the chart override + * this method and add your subtitles manually. + * + * @param chart The JFreeChart chart object. + */ + protected void addSubtitles(JFreeChart chart) { + String subtitle = getChartSubtitle(); + + if (subtitle != null && subtitle.length() > 0) { + chart.addSubtitle(new TextTitle(subtitle)); + } + } + + + /** + * Register annotations like MainValues for later plotting + * + * @param annotations list of annotations (data of facet). + * @param aandf Artifact and the facet. + * @param theme Theme document for given annotations. + * @param visible The visibility of the annotations. + */ + protected void doAnnotations( + FLYSAnnotation annotations, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ){ + logger.debug("doAnnotations"); + + // Add all annotations to our annotation pool. + annotations.setTheme(theme); + if (aandf != null) { + annotations.setLabel(aandf.getFacetDescription()); + } + else { + logger.debug( + "Art/Facet for Annotations is null. " + + "This should never happen!"); + } + + if (visible) { + addAnnotations(annotations); + } + } + + + /** + * Generate chart. + */ + @Override + public void generate() + throws IOException + { + logger.debug("ChartGenerator.generate"); + + JFreeChart chart = generateChart(); + + String format = getFormat(); + int[] size = getSize(); + + if (size == null) { + size = getExportDimension(); + } + + context.putContextValue("chart.width", size[0]); + context.putContextValue("chart.height", size[1]); + + if (format.equals(ChartExportHelper.FORMAT_PNG)) { + context.putContextValue("chart.image.format", "png"); + + ChartExportHelper.exportImage( + out, + chart, + context); + } + else if (format.equals(ChartExportHelper.FORMAT_PDF)) { + preparePDFContext(context); + + ChartExportHelper.exportPDF( + out, + chart, + context); + } + else if (format.equals(ChartExportHelper.FORMAT_SVG)) { + prepareSVGContext(context); + + ChartExportHelper.exportSVG( + out, + chart, + context); + } + else if (format.equals(ChartExportHelper.FORMAT_CSV)) { + context.putContextValue("chart.image.format", "csv"); + + ChartExportHelper.exportCSV( + out, + chart, + context); + } + } + + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("ChartGenerator.init"); + + this.request = request; + this.out = out; + this.context = context; + } + + + @Override + public void setMasterArtifact(Artifact master) { + this.master = master; + } + + + @Override + public void setCollection(FLYSArtifactCollection collection) { + this.collection = collection; + } + + + @Override + public void setSettings(Settings settings) { + this.settings = settings; + } + + + /** + * Returns an instance of <i>ChartSettings</i> with a chart specific section + * but with no axes settings. + * + * @return an instance of <i>ChartSettings</i>. + */ + @Override + public Settings getSettings() { + if (this.settings != null) { + return this.settings; + } + + ChartSettings settings = new ChartSettings(); + + ChartSection chartSection = buildChartSection(); + LegendSection legendSection = buildLegendSection(); + ExportSection exportSection = buildExportSection(); + + settings.setChartSection(chartSection); + settings.setLegendSection(legendSection); + settings.setExportSection(exportSection); + + List<AxisSection> axisSections = buildAxisSections(); + for (AxisSection axisSection: axisSections) { + settings.addAxisSection(axisSection); + } + + return settings; + } + + + /** + * Creates a new <i>ChartSection</i>. + * + * @return a new <i>ChartSection</i>. + */ + protected ChartSection buildChartSection() { + ChartSection chartSection = new ChartSection(); + chartSection.setTitle(getChartTitle()); + chartSection.setSubtitle(getChartSubtitle()); + chartSection.setDisplayGrid(isGridVisible()); + chartSection.setDisplayLogo(showLogo()); + chartSection.setLogoVPlacement(logoVPlace()); + chartSection.setLogoHPlacement(logoHPlace()); + return chartSection; + } + + + /** + * Creates a new <i>LegendSection</i>. + * + * @return a new <i>LegendSection</i>. + */ + protected LegendSection buildLegendSection() { + LegendSection legendSection = new LegendSection(); + legendSection.setVisibility(isLegendVisible()); + legendSection.setFontSize(getLegendFontSize()); + legendSection.setAggregationThreshold(10); + return legendSection; + } + + + /** + * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b> + * and <b>HEIGHT=400</b>. + * + * @return a new <i>ExportSection</i>. + */ + protected ExportSection buildExportSection() { + ExportSection exportSection = new ExportSection(); + exportSection.setWidth(600); + exportSection.setHeight(400); + return exportSection; + } + + + /** + * Creates a list of Sections that contains all axes of the chart (including + * X and Y axes). + * + * @return a list of Sections for each axis in this chart. + */ + protected List<AxisSection> buildAxisSections() { + List<AxisSection> axisSections = new ArrayList<AxisSection>(); + + axisSections.addAll(buildXAxisSections()); + axisSections.addAll(buildYAxisSections()); + + return axisSections; + } + + + /** + * Creates a new Section for chart's X axis. + * + * @return a List that contains a Section for the X axis. + */ + protected List<AxisSection> buildXAxisSections() { + List<AxisSection> axisSections = new ArrayList<AxisSection>(); + + String identifier = "X"; + + AxisSection axisSection = new AxisSection(); + axisSection.setIdentifier(identifier); + axisSection.setLabel(getXAxisLabel()); + axisSection.setFontSize(14); + axisSection.setFixed(false); + + // XXX We are able to find better default ranges that [0,0], but the Y + // axes currently have no better ranges set. + axisSection.setUpperRange(0d); + axisSection.setLowerRange(0d); + + axisSections.add(axisSection); + + return axisSections; + } + + + /** + * Creates a list of Section for the chart's Y axes. This method makes use + * of <i>getYAxisWalker</i> to be able to access all Y axes defined in + * subclasses. + * + * @return a list of Y axis sections. + */ + protected List<AxisSection> buildYAxisSections() { + List<AxisSection> axisSections = new ArrayList<AxisSection>(); + + YAxisWalker walker = getYAxisWalker(); + for (int i = 0, n = walker.length(); i < n; i++) { + AxisSection ySection = new AxisSection(); + ySection.setIdentifier(walker.getId(i)); + ySection.setLabel(getYAxisLabel(i)); + ySection.setFontSize(14); + ySection.setFixed(false); + + // XXX We are able to find better default ranges that [0,0], the + // only problem is, that we do NOT have a better range than [0,0] + // for each axis, because the initial chart will not have a dataset + // for each axis set! + ySection.setUpperRange(0d); + ySection.setLowerRange(0d); + + axisSections.add(ySection); + } + + return axisSections; + } + + + /** + * Returns the <i>settings</i> as <i>ChartSettings</i>. + * + * @return the <i>settings</i> as <i>ChartSettings</i> or null, if + * <i>settings</i> is not an instance of <i>ChartSettings</i>. + */ + public ChartSettings getChartSettings() { + if (settings instanceof ChartSettings) { + return (ChartSettings) settings; + } + + return null; + } + + + /** + * Returns the chart title provided by <i>settings</i>. + * + * @param settings A ChartSettings object. + * + * @return the title provided by <i>settings</i> or null if no + * <i>ChartSection</i> is provided by <i>settings</i>. + * + * @throws NullPointerException if <i>settings</i> is null. + */ + public String getChartTitle(ChartSettings settings) { + ChartSection cs = settings.getChartSection(); + return cs != null ? cs.getTitle() : null; + } + + + /** + * Returns the chart subtitle provided by <i>settings</i>. + * + * @param settings A ChartSettings object. + * + * @return the subtitle provided by <i>settings</i> or null if no + * <i>ChartSection</i> is provided by <i>settings</i>. + * + * @throws NullPointerException if <i>settings</i> is null. + */ + public String getChartSubtitle(ChartSettings settings) { + ChartSection cs = settings.getChartSection(); + return cs != null ? cs.getSubtitle() : null; + } + + + /** + * Returns a boolean object that determines if the chart grid should be + * visible or not. This information needs to be provided by <i>settings</i>, + * otherweise the default is true. + * + * @param settings A ChartSettings object. + * + * @return true, if the chart grid should be visible otherwise false. + * + * @throws NullPointerException if <i>settings</i> is null. + */ + public boolean isGridVisible(ChartSettings settings) { + ChartSection cs = settings.getChartSection(); + Boolean displayGrid = cs.getDisplayGrid(); + + return displayGrid != null ? displayGrid : true; + } + + + /** + * Returns a boolean object that determines if the chart legend should be + * visible or not. This information needs to be provided by <i>settings</i>, + * otherwise the default is true. + * + * @param settings A ChartSettings object. + * + * @return true, if the chart legend should be visible otherwise false. + * + * @throws NullPointerException if <i>settings</i> is null. + */ + public boolean isLegendVisible(ChartSettings settings) { + LegendSection ls = settings.getLegendSection(); + Boolean displayLegend = ls.getVisibility(); + + return displayLegend != null ? displayLegend : true; + } + + + /** + * Returns the legend font size specified in <i>settings</i> or null if no + * <i>LegendSection</i> is provided by <i>settings</i>. + * + * @param settings A ChartSettings object. + * + * @return the legend font size or null. + * + * @throws NullPointerException if <i>settings</i> is null. + */ + public Integer getLegendFontSize(ChartSettings settings) { + LegendSection ls = settings.getLegendSection(); + return ls != null ? ls.getFontSize() : null; + } + + + /** + * Returns the title of a chart. The return value depends on the existence + * of ChartSettings: if there are ChartSettings set, this method returns the + * chart title provided by those settings. Otherwise, this method returns + * getDefaultChartTitle(). + * + * @return the title of a chart. + */ + protected String getChartTitle() { + ChartSettings chartSettings = getChartSettings(); + + if (chartSettings != null) { + return getChartTitle(chartSettings); + } + + return getDefaultChartTitle(); + } + + + /** + * Returns the subtitle of a chart. The return value depends on the + * existence of ChartSettings: if there are ChartSettings set, this method + * returns the chart title provided by those settings. Otherwise, this + * method returns getDefaultChartSubtitle(). + * + * @return the subtitle of a chart. + */ + protected String getChartSubtitle() { + ChartSettings chartSettings = getChartSettings(); + + if (chartSettings != null) { + return getChartSubtitle(chartSettings); + } + + return getDefaultChartSubtitle(); + } + + + /** + * This method always returns null. Override it in subclasses that require + * subtitles. + * + * @return null. + */ + protected String getDefaultChartSubtitle() { + // Override this method in subclasses + return null; + } + + + /** + * This method is used to determine, if the chart's legend is visible or + * not. If a <i>settings</i> instance is set, this instance determines the + * visibility otherwise, this method returns true as default if no + * <i>settings</i> is set. + * + * @return true, if the legend should be visible, otherwise false. + */ + protected boolean isLegendVisible() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + return isLegendVisible(chartSettings); + } + + return true; + } + + + /** Where to place the logo. */ + protected String logoHPlace() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + ChartSection cs = chartSettings.getChartSection(); + String place = cs.getLogoHPlacement(); + + return place; + } + return "center"; + } + + + /** Where to place the logo. */ + protected String logoVPlace() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + ChartSection cs = chartSettings.getChartSection(); + String place = cs.getLogoVPlacement(); + + return place; + } + return "top"; + } + + + /** Return the logo id from settings. */ + protected String showLogo(ChartSettings chartSettings) { + if (chartSettings != null) { + ChartSection cs = chartSettings.getChartSection(); + String logo = cs.getDisplayLogo(); + + return logo; + } + return "none"; + } + + + /** + * This method is used to determine if a logo should be added to the plot. + * + * @return logo name (null if none). + */ + protected String showLogo() { + ChartSettings chartSettings = getChartSettings(); + return showLogo(chartSettings); + } + + + /** + * This method is used to determine the font size of the chart's legend. If + * a <i>settings</i> instance is set, this instance determines the font + * size, otherwise this method returns 12 as default if no <i>settings</i> + * is set or if it doesn't provide a legend font size. + * + * @return a legend font size. + */ + protected int getLegendFontSize() { + Integer fontSize = null; + + ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + fontSize = getLegendFontSize(chartSettings); + } + + return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; + } + + + /** + * This method is used to determine if the resulting chart should display + * grid lines or not. <b>Note: this method always returns true!</b> + * + * @return true, if the chart should display grid lines, otherwise false. + */ + protected boolean isGridVisible() { + return true; + } + + + /** + * Returns the X-Axis label of a chart. + * + * @return the X-Axis label of a chart. + */ + protected String getXAxisLabel() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return getDefaultXAxisLabel(); + } + + AxisSection as = chartSettings.getAxisSection("X"); + if (as != null) { + String label = as.getLabel(); + + if (label != null) { + return label; + } + } + + return getDefaultXAxisLabel(); + } + + + /** + * This method returns the font size for the X axis. If the font size is + * specified in ChartSettings (if <i>chartSettings</i> is set), this size is + * returned. Otherwise the default font size 12 is returned. + * + * @return the font size for the x axis. + */ + protected int getXAxisLabelFontSize() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return DEFAULT_FONT_SIZE; + } + + AxisSection as = chartSettings.getAxisSection("X"); + Integer fontSize = as.getFontSize(); + + return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; + } + + + /** + * This method returns the font size for an Y axis. If the font size is + * specified in ChartSettings (if <i>chartSettings</i> is set), this size is + * returned. Otherwise the default font size 12 is returned. + * + * @return the font size for the x axis. + */ + protected int getYAxisFontSize(int pos) { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return DEFAULT_FONT_SIZE; + } + + YAxisWalker walker = getYAxisWalker(); + + AxisSection as = chartSettings.getAxisSection(walker.getId(pos)); + Integer fontSize = as.getFontSize(); + + return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; + } + + + /** + * This method returns the export dimension specified in ChartSettings as + * int array [width,height]. + * + * @return an int array with [width,height]. + */ + protected int[] getExportDimension() { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return new int[] { 600, 400 }; + } + + ExportSection export = chartSettings.getExportSection(); + Integer width = export.getWidth(); + Integer height = export.getHeight(); + + if (width != null && height != null) { + return new int[] { width, height }; + } + + return new int[] { 600, 400 }; + } + + + /** + * Returns the Y-Axis label of a chart at position <i>pos</i>. + * + * @return the Y-Axis label of a chart at position <i>0</i>. + */ + protected String getYAxisLabel(int pos) { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return getDefaultYAxisLabel(pos); + } + + YAxisWalker walker = getYAxisWalker(); + AxisSection as = chartSettings.getAxisSection(walker.getId(pos)); + if (as != null) { + String label = as.getLabel(); + + if (label != null) { + return label; + } + } + + return getDefaultYAxisLabel(pos); + } + + + /** + * This method searches for a specific axis in the <i>settings</i> if + * <i>settings</i> is set. If the axis was found, this method returns the + * specified axis range if the axis range is fixed. Otherwise, this method + * returns null. + * + * @param axisId The identifier of an axis. + * + * @return the specified axis range from <i>settings</i> if the axis is + * fixed, otherwise null. + */ + public Range getRangeForAxisFromSettings(String axisId) { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return null; + } + + AxisSection as = chartSettings.getAxisSection(axisId); + Boolean fixed = as.isFixed(); + + if (fixed != null && fixed) { + Double upper = as.getUpperRange(); + Double lower = as.getLowerRange(); + + if (upper != null && lower != null) { + return lower < upper + ? new Range(lower, upper) + : new Range(upper, lower); + } + } + + return null; + } + + + /** + * Adds a new AxisDataset which contains <i>dataset</i> at index <i>idx</i>. + * + * @param dataset An XYDataset. + * @param idx The axis index. + * @param visible Determines, if the dataset should be visible or not. + */ + public void addAxisDataset(XYDataset dataset, int idx, boolean visible) { + if (dataset == null || idx < 0) { + return; + } + + AxisDataset axisDataset = getAxisDataset(idx); + + Bounds[] xyBounds = ChartHelper.getBounds(dataset); + + if (xyBounds == null) { + logger.warn("Skip XYDataset for Axis (invalid ranges): " + idx); + return; + } + + if (visible) { + if (logger.isDebugEnabled()) { + logger.debug("Add new AxisDataset at index: " + idx); + logger.debug("X extent: " + xyBounds[0]); + logger.debug("Y extent: " + xyBounds[1]); + } + + axisDataset.addDataset(dataset); + } + + combineXBounds(xyBounds[0], 0); + combineYBounds(xyBounds[1], idx); + } + + + /** + * This method grants access to the AxisDatasets stored in <i>datasets</i>. + * If no AxisDataset exists for index <i>idx</i>, a new AxisDataset is + * created using <i>createAxisDataset()</i>. + * + * @param idx The index of the desired AxisDataset. + * + * @return an existing or new AxisDataset. + */ + public AxisDataset getAxisDataset(int idx) { + AxisDataset axisDataset = datasets.get(idx); + + if (axisDataset == null) { + axisDataset = createAxisDataset(idx); + datasets.put(idx, axisDataset); + } + + return axisDataset; + } + + + /** + * Adjust some Stroke/Grid parameters for <i>plot</i>. The chart + * <i>Settings</i> are applied in this method. + * + * @param plot The XYPlot which is adapted. + */ + protected void adjustPlot(XYPlot plot) { + Stroke gridStroke = new BasicStroke( + DEFAULT_GRID_LINE_WIDTH, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 3.0f, + new float[] { 3.0f }, + 0.0f); + + ChartSettings cs = getChartSettings(); + boolean isGridVisible = cs != null ? isGridVisible(cs) : true; + + plot.setDomainGridlineStroke(gridStroke); + plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR); + plot.setDomainGridlinesVisible(isGridVisible); + + plot.setRangeGridlineStroke(gridStroke); + plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR); + plot.setRangeGridlinesVisible(isGridVisible); + + plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d)); + } + + + /** + * This helper mehtod is used to extract the current locale from instance + * vairable <i>context</i>. + * + * @return the current locale. + */ + protected Locale getLocale() { + CallMeta meta = context.getMeta(); + PreferredLocale[] prefs = meta.getLanguages(); + + int len = prefs != null ? prefs.length : 0; + + Locale[] locales = new Locale[len]; + + for (int i = 0; i < len; i++) { + locales[i] = prefs[i].getLocale(); + } + + return meta.getPreferredLocale(locales); + } + + + protected String msg(String key, String def) { + return Resources.getMsg(context.getMeta(), key, def); + } + + protected String msg(String key) { + return Resources.getMsg(context.getMeta(), key, key); + } + + protected String msg(String key, String def, Object[] args) { + return Resources.getMsg(context.getMeta(), key, def, args); + } + + + protected String getRiverName() { + FLYSArtifact flys = (FLYSArtifact) master; + + River river = FLYSUtils.getRiver(flys); + return (river != null) ? river.getName() : ""; + } + + + protected double[] getRange() { + FLYSArtifact flys = (FLYSArtifact) master; + + return FLYSUtils.getKmRange(flys); + } + + + /** + * Returns the size of a chart export as array which has been specified by + * the incoming request document. + * + * @return the size of a chart as [width, height] or null if no width or + * height are given in the request document. + */ + protected int[] getSize() { + int[] size = new int[2]; + + Element sizeEl = (Element)XMLUtils.xpath( + request, + XPATH_CHART_SIZE, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (sizeEl != null) { + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + String w = sizeEl.getAttributeNS(uri, "width"); + String h = sizeEl.getAttributeNS(uri, "height"); + + if (w.length() > 0 && h.length() > 0) { + try { + size[0] = Integer.parseInt(w); + size[1] = Integer.parseInt(h); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for chart width/height."); + } + } + } + + return size[0] > 0 && size[1] > 0 ? size : null; + } + + + /** + * This method returns the format specified in the <i>request</i> document + * or <i>DEFAULT_CHART_FORMAT</i> if no format is specified in + * <i>request</i>. + * + * @return the format used to export this chart. + */ + protected String getFormat() { + String format = (String) XMLUtils.xpath( + request, + XPATH_CHART_FORMAT, + XPathConstants.STRING, + ArtifactNamespaceContext.INSTANCE); + + return format == null || format.length() == 0 + ? DEFAULT_CHART_FORMAT + : format; + } + + + /** + * Returns the X-Axis range as String array from request document. + * + * @return a String array with [lower, upper]. + */ + protected String[] getDomainAxisRangeFromRequest() { + Element xrange = (Element)XMLUtils.xpath( + request, + XPATH_CHART_X_RANGE, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (xrange == null) { + return null; + } + + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + String lower = xrange.getAttributeNS(uri, "from"); + String upper = xrange.getAttributeNS(uri, "to"); + + return new String[] { lower, upper }; + } + + + protected String[] getValueAxisRangeFromRequest() { + Element yrange = (Element)XMLUtils.xpath( + request, + XPATH_CHART_Y_RANGE, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (yrange == null) { + return null; + } + + + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + String lower = yrange.getAttributeNS(uri, "from"); + String upper = yrange.getAttributeNS(uri, "to"); + + return new String[] { lower, upper }; + } + + + /** + * Returns the default size of a chart export as array. + * + * @return the default size of a chart as [width, height]. + */ + protected int[] getDefaultSize() { + return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; + } + + + /** + * Add datasets stored in instance variable <i>datasets</i> to plot. + * <i>datasets</i> actually stores instances of AxisDataset, so each of this + * datasets is mapped to a specific axis as well. + * + * @param plot plot to add datasets to. + */ + protected void addDatasets(XYPlot plot) { + logger.debug("addDatasets()"); + + // AxisDatasets are sorted, but some might be empty. + // Thus, generate numbering on the fly. + int axisIndex = 0; + int datasetIndex = 0; + + for (Map.Entry<Integer, AxisDataset> entry: datasets.entrySet()) { + if (!entry.getValue().isEmpty()) { + // Add axis and range information. + AxisDataset axisDataset = entry.getValue(); + NumberAxis axis = createYAxis(entry.getKey()); + + plot.setRangeAxis(axisIndex, axis); + + if (axis.getAutoRangeIncludesZero()) { + axisDataset.setRange( + Range.expandToInclude(axisDataset.getRange(), 0d)); + } + + setYBounds(axisIndex, expandPointRange(axisDataset.getRange())); + + // Add contained datasets, mapping to axis. + for (XYDataset dataset: axisDataset.getDatasets()) { + plot.setDataset(datasetIndex, dataset); + plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); + + applyThemes(plot, dataset, + datasetIndex, + axisDataset.isArea(dataset)); + + datasetIndex++; + } + + axisDataset.setPlotAxisIndex(axisIndex); + axisIndex++; + } + } + } + + + /** + * @param idx "index" of dataset/series (first dataset to be drawn has + * index 0), correlates with renderer index. + * @param isArea true if the series describes an area and shall be rendered + * as such. + */ + protected void applyThemes( + XYPlot plot, + XYDataset series, + int idx, + boolean isArea + ) { + if (isArea) { + applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx); + } + else { + applyLineTheme(plot, series, idx); + } + } + + + /** + * This method applies the themes defined in the series itself. Therefore, + * <i>StyledXYSeries.applyTheme()</i> is called, which modifies the renderer + * for the series. + * + * @param plot The plot. + * @param dataset The XYDataset which needs to support Series objects. + * @param idx The index of the renderer / dataset. + */ + protected void applyLineTheme(XYPlot plot, XYDataset dataset, int idx) { + logger.debug("Apply LineTheme for dataset at index: " + idx); + + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection anno = plot.getFixedLegendItems(); + + Font legendFont = createLegendLabelFont(); + + XYLineAndShapeRenderer renderer = createRenderer(plot, idx); + + for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { + Series series = getSeriesOf(dataset, s); + + if (series instanceof StyledSeries) { + Style style = ((StyledSeries) series).getStyle(); + style.applyTheme(renderer, s); + } + + // special case: if there is just one single item, we need to enable + // points for this series, otherwise we would not see anything in + // the chart area. + if (series.getItemCount() == 1) { + renderer.setSeriesShapesVisible(s, true); + } + + LegendItem legendItem = renderer.getLegendItem(idx, s); + if (legendItem.getLabel().endsWith(" ") || + legendItem.getLabel().endsWith("interpol")) { + legendItem = null; + } + + if (legendItem != null) { + legendItem.setLabelFont(legendFont); + lic.add(legendItem); + } + else { + logger.warn("Could not get LegentItem for renderer: " + + idx + ", series-idx " + s); + } + } + + if (anno != null) { + lic.addAll(anno); + } + + plot.setFixedLegendItems(lic); + + plot.setRenderer(idx, renderer); + } + + + /** + * @param plot The plot. + * @param area A StyledAreaSeriesCollection object. + * @param idx The index of the dataset. + */ + protected void applyAreaTheme( + XYPlot plot, + StyledAreaSeriesCollection area, + int idx + ) { + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection anno = plot.getFixedLegendItems(); + + Font legendFont = createLegendLabelFont(); + + logger.debug("Registering an 'area'renderer at idx: " + idx); + + StableXYDifferenceRenderer dRenderer = + new StableXYDifferenceRenderer(); + + if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { + dRenderer.setPositivePaint(createTransparentPaint()); + } + + plot.setRenderer(idx, dRenderer); + + area.applyTheme(dRenderer); + + // i18n + dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(context.getMeta(), 2, 4)); + + dRenderer.setAreaLabelTemplate(Resources.getMsg( + context.getMeta(), "area.label.template", "Area=%sm2")); + + LegendItem legendItem = dRenderer.getLegendItem(idx, 0); + if (legendItem != null) { + legendItem.setLabelFont(legendFont); + lic.add(legendItem); + } + else { + logger.warn("Could not get LegentItem for renderer: " + + idx + ", series-idx " + 0); + } + + if (anno != null) { + lic.addAll(anno); + } + + plot.setFixedLegendItems(lic); + } + + + /** + * Expands a given range if it collapses into one point. + * + * @param range Range to be expanded if upper == lower bound. + * + * @return Bounds of point plus 5 percent in each direction. + */ + private Bounds expandPointRange(Range range) { + if (range == null) { + return null; + } + else if (range.getLowerBound() == range.getUpperBound()) { + Range expandedRange = ChartHelper.expandRange(range, 5d); + return new DoubleBounds(expandedRange.getLowerBound(), expandedRange.getUpperBound()); + } + + return new DoubleBounds(range.getLowerBound(), range.getUpperBound()); + } + + + /** + * Creates a new instance of EnhancedLineAndShapeRenderer. + * + * @param plot The plot which is set for the new renderer. + * @param idx This value is not used in the current implementation. + * + * @return a new instance of EnhancedLineAndShapeRenderer. + */ + protected XYLineAndShapeRenderer createRenderer(XYPlot plot, int idx) { + logger.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx); + + EnhancedLineAndShapeRenderer r = + new EnhancedLineAndShapeRenderer(true, false); + + r.setPlot(plot); + + return r; + } + + + /** + * Creates a new instance of <i>IdentifiableNumberAxis</i>. + * + * @param idx The index of the new axis. + * @param label The label of the new axis. + * + * @return an instance of IdentifiableNumberAxis. + */ + protected NumberAxis createNumberAxis(int idx, String label) { + YAxisWalker walker = getYAxisWalker(); + + return new IdentifiableNumberAxis(walker.getId(idx), label); + } + + + /** + * Create Y (range) axis for given index. + * Shall be overriden by subclasses. + */ + protected NumberAxis createYAxis(int index) { + YAxisWalker walker = getYAxisWalker(); + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getYAxisFontSize(index)); + + IdentifiableNumberAxis axis = new IdentifiableNumberAxis( + walker.getId(index), + getYAxisLabel(index)); + + axis.setAutoRangeIncludesZero(false); + axis.setLabelFont(labelFont); + axis.setTickLabelFont(labelFont); + + return axis; + } + + + /** + * Creates a new LegendItem with <i>name</i> and font provided by + * <i>createLegendLabelFont()</i>. + * + * @param theme The theme of the chart line. + * @param name The displayed name of the item. + * + * @return a new LegendItem instance. + */ + public LegendItem createLegendItem(Document theme, String name) { + // OPTIMIZE Pass font, parsed Theme items. + ThemeAccess themeAccess = new ThemeAccess(theme); + + Color color = themeAccess.parseLineColorField(); + LegendItem legendItem = new LegendItem(name, color); + + legendItem.setLabelFont(createLegendLabelFont()); + return legendItem; + } + + + /** + * Creates Font (Family and size) to use when creating Legend Items. The + * font size depends in the return value of <i>getLegendFontSize()</i>. + * + * @return a new Font instance with <i>DEFAULT_FONT_NAME</i>. + */ + protected Font createLegendLabelFont() { + return new Font( + DEFAULT_FONT_NAME, + Font.PLAIN, + getLegendFontSize() + ); + } + + + /** + * Create new legend entries, dependent on settings. + * @param plot The plot for which to modify the legend. + */ + public void aggregateLegendEntries(XYPlot plot) { + int AGGR_THRESHOLD = 0; + + if (getChartSettings() == null) { + return; + } + Integer threshold = getChartSettings().getLegendSection() + .getAggregationThreshold(); + + AGGR_THRESHOLD = (threshold != null) ? threshold.intValue() : 0; + + LegendProcessor.aggregateLegendEntries(plot, AGGR_THRESHOLD); + } + + + /** + * Returns a transparently textured paint. + * + * @return a transparently textured paint. + */ + protected static Paint createTransparentPaint() { + // TODO why not use a transparent color? + BufferedImage texture = new BufferedImage( + 1, 1, BufferedImage.TYPE_4BYTE_ABGR); + + return new TexturePaint( + texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); + } + + + protected void preparePDFContext(CallContext context) { + int[] dimension = getExportDimension(); + + context.putContextValue("chart.width", dimension[0]); + context.putContextValue("chart.height", dimension[1]); + context.putContextValue("chart.marginLeft", 5f); + context.putContextValue("chart.marginRight", 5f); + context.putContextValue("chart.marginTop", 5f); + context.putContextValue("chart.marginBottom", 5f); + context.putContextValue( + "chart.page.format", + ChartExportHelper.DEFAULT_PAGE_SIZE); + } + + + protected void prepareSVGContext(CallContext context) { + int[] dimension = getExportDimension(); + + context.putContextValue("chart.width", dimension[0]); + context.putContextValue("chart.height", dimension[1]); + context.putContextValue( + "chart.encoding", + ChartExportHelper.DEFAULT_ENCODING); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartHelper.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,200 @@ +package de.intevation.flys.exports; + +import org.jfree.data.Range; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.time.TimeSeries; + +import org.apache.log4j.Logger; + +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.DoubleBounds; +import de.intevation.flys.jfree.TimeBounds; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChartHelper { + + private static final Logger logger = Logger.getLogger(ChartHelper.class); + + + /** + * This method returns the ranges of the XYDataset <i>dataset</i> as array + * with [xrange, yrange]. + * + * @param dataset The dataset which should be evaluated. + * + * @return an array with x and y ranges. + */ + public static Bounds[] getBounds(XYSeriesCollection dataset) { + int seriesCount = dataset != null ? dataset.getSeriesCount() : 0; + + if (seriesCount == 0) { + logger.warn("Dataset is empty or has no Series set."); + return null; + } + + boolean foundValue = false; + + double minX = Double.MAX_VALUE; + double maxX = -Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxY = -Double.MAX_VALUE; + + for (int i = 0, m = seriesCount; i < m; i++) { + for (int j = 0, n = dataset.getItemCount(i); j < n; j++) { + double x = dataset.getXValue(i, j); + double y = dataset.getYValue(i, j); + + if (Double.isNaN(x) || Double.isNaN(y)) { + logger.warn("Item " + j + " in Series " + i + " is broken"); + continue; + } + + foundValue = true; + + if (x < minX) { + minX = x; + } + + if (x > maxX) { + maxX = x; + } + + if (y < minY) { + minY = y; + } + + if (y > maxY) { + maxY = y; + } + } + } + + return foundValue + ? new Bounds[] { + new DoubleBounds(minX, maxX), + new DoubleBounds(minY, maxY) } + : null; + } + + + public static Bounds[] getBounds(XYDataset dataset) { + if (dataset instanceof XYSeriesCollection) { + return getBounds((XYSeriesCollection) dataset); + } + else if(dataset instanceof TimeSeriesCollection) { + return getBounds((TimeSeriesCollection) dataset); + } + else { + logger.warn("Unknown XYDataset instance: " + dataset.getClass()); + return null; + } + } + + + public static Bounds[] getBounds(TimeSeriesCollection collection) { + int seriesCount = collection != null ? collection.getSeriesCount() : 0; + + if (seriesCount == 0) { + logger.warn("TimeSeriesCollection is empty or has no Series set."); + return null; + } + + boolean foundValue = false; + + long lowerX = Long.MAX_VALUE; + long upperX = -Long.MAX_VALUE; + + double lowerY = Double.MAX_VALUE; + double upperY = -Double.MAX_VALUE; + + for (int i = 0, m = seriesCount; i < m; i++) { + TimeSeries series = collection.getSeries(i); + + for (int j = 0, n = collection.getItemCount(i); j < n; j++) { + RegularTimePeriod rtp = series.getTimePeriod(j); + + if (rtp == null) { + continue; + } + + foundValue = true; + + long start = rtp.getFirstMillisecond(); + long end = rtp.getLastMillisecond(); + + if (start < lowerX) { + lowerX = start; + } + + if (end > upperX) { + upperX = end; + } + + double y = series.getValue(j).doubleValue(); + + lowerY = Math.min(lowerY, y); + upperY = Math.max(upperY, y); + } + } + + if (foundValue) { + return new Bounds[] { + new TimeBounds(lowerX, upperX), + new DoubleBounds(lowerY, upperY) + }; + } + + return null; + } + + + /** + * Expand bounds by percent. + * + * @param bounds The bounds to expand. + * @param percent The percentage to expand. + * + * @return a new, expanded bounds. + */ + public static Bounds expandBounds(Bounds bounds, double percent) { + if (bounds == null) { + return null; + } + + double value = (Double) bounds.getLower(); + double expand = Math.abs(value / 100 * percent); + + return expand != 0 + ? new DoubleBounds(value-expand, value+expand) + : new DoubleBounds(-0.01 * percent, 0.01 * percent); + } + + + /** + * Expand range by percent. + * + * @param range The range to expand. + * @param percent The percentage to expand. + * + * @return a new, expanded range. + */ + public static Range expandRange(Range range, double percent) { + if (range == null) { + return null; + } + + double value = range.getLowerBound(); + double expand = Math.abs(value / 100 * percent); + + return expand != 0 + ? new Range(value-expand, value+expand) + : new Range(-0.01 * percent, 0.01 * percent); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,189 @@ +package de.intevation.flys.exports; + +import de.intevation.flys.collections.FLYSArtifactCollection; +import de.intevation.flys.java2d.NOPGraphics2D; + +import java.io.IOException; +import java.io.OutputStream; + +import java.awt.Transparency; +import java.awt.Graphics2D; + +import java.awt.geom.Rectangle2D; + +import java.awt.image.BufferedImage; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.JFreeChart; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; + +import de.intevation.artifacts.common.utils.XMLUtils; + + +/** + * An OutGenerator that generates meta information for charts. A concrete + * ChartInfoGenerator need to instantiate a concrete ChartGenerator and dispatch + * the methods to that instance. The only thing this ChartInfoGenerator needs + * to, is to overwrite the generate() method which doesn't write the chart image + * to the OutputStream but a Document that contains some meta information of the + * created chart. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class ChartInfoGenerator implements OutGenerator { + + public static final boolean USE_NOP_GRAPHICS = + Boolean.getBoolean("info.rendering.nop.graphics"); + + /** The logger used in this generator.*/ + private static Logger logger = + Logger.getLogger(ChartInfoGenerator.class); + + + /** The OutGenerator that creates the charts.*/ + protected ChartGenerator generator; + + protected OutputStream out; + + + + public ChartInfoGenerator(ChartGenerator generator) { + this.generator = generator; + } + + + /** + * Dispatches the operation to the instantiated generator. + * + * @param request + * @param out + * @param context + */ + public void init(Document request, OutputStream out, CallContext context) { + this.out = out; + + generator.init(request, out, context); + } + + + /** + * Dispatches the operation to the instantiated generator. + * + * @param master The master artifact + */ + public void setMasterArtifact(Artifact master) { + generator.setMasterArtifact(master); + } + + + /** + * Dispatches the operation to the instantiated generator. + * + * @param collection The collection. + */ + public void setCollection(FLYSArtifactCollection collection) { + generator.setCollection(collection); + } + + + /** + * Dispatches the operation to the instantiated generator. + */ + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + generator.doOut(artifactFacet, attr, visible); + } + + + /** + * This method generates the chart using a concrete ChartGenerator but + * doesn't write the chart itself to the OutputStream but a Document that + * contains meta information of the created chart. + */ + @Override + public void generate() + throws IOException + { + logger.debug("ChartInfoGenerator.generate"); + + JFreeChart chart = generator.generateChart(); + + int[] size = generator.getSize(); + if (size == null) { + size = generator.getDefaultSize(); + } + + ChartRenderingInfo info = new ChartRenderingInfo(); + + long startTime = System.currentTimeMillis(); + + if (USE_NOP_GRAPHICS) { + BufferedImage image = + new BufferedImage(size[0], size[1], Transparency.BITMASK); + + Graphics2D g2d = image.createGraphics(); + Graphics2D nop = new NOPGraphics2D(g2d); + + chart.draw( + nop, + new Rectangle2D.Double(0, 0, size[0], size[1]), + null, + info); + + nop.dispose(); + } + else { + chart.createBufferedImage( + size[0], size[1], Transparency.BITMASK, info); + } + + long stopTime = System.currentTimeMillis(); + + if (logger.isDebugEnabled()) { + logger.debug("Rendering info took: " + + (stopTime-startTime) + "ms"); + } + + + InfoGeneratorHelper helper = new InfoGeneratorHelper(generator); + Document doc = helper.createInfoDocument(chart, info); + + XMLUtils.toStream(doc, out); + } + + + /** + * A proxy method which calls <i>generator</i>.getSettings() and returns its + * return value. + * + * @return a Settings object provided by <i>generator</i>. + */ + @Override + public Settings getSettings() { + return generator.getSettings(); + } + + + /** + * A proxy method which calls <i>generator</i>.setSettings(). + * + * @param settings A settings object for the <i>generator</i>. + */ + @Override + public void setSettings(Settings settings) { + generator.setSettings(settings); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,92 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChartSection extends TypeSection { + + private static Logger logger = Logger.getLogger(ChartSection.class); + + public static final String TITLE_ATTR = "title"; + public static final String SUBTITLE_ATTR = "subtitle"; + public static final String DISPLAYGRID_ATTR = "display-grid"; + public static final String DISPLAYLOGO_ATTR = "display-logo"; + public static final String LOGOPLACEMENTH_ATTR = "logo-placeh"; + public static final String LOGOPLACEMENTV_ATTR = "logo-placev"; + + + public ChartSection() { + super("chart"); + } + + + public void setTitle(String title) { + setStringValue(TITLE_ATTR, title); + } + + + public String getTitle() { + return getStringValue(TITLE_ATTR); + } + + + public void setSubtitle(String subtitle) { + setStringValue(SUBTITLE_ATTR, subtitle); + } + + + public String getSubtitle() { + return getStringValue(SUBTITLE_ATTR); + } + + + /** Get Property-value for display-logo property. */ + public String getDisplayLogo() { + return getStringValue(DISPLAYLOGO_ATTR); + } + + + /** Set Property-value for display-logo property. */ + public void setDisplayLogo(String logo) { + logger.debug("Setting Display logo string."); + setChoiceStringValue(DISPLAYLOGO_ATTR, logo, "logo"); + } + + + /** Get Property-value for horizontal logo-placement property. */ + public String getLogoHPlacement() { + return getStringValue(LOGOPLACEMENTH_ATTR); + } + + + /** Set Property-value for horizontal logo-placement property. */ + public void setLogoHPlacement(String place) { + setChoiceStringValue(LOGOPLACEMENTH_ATTR, place, "placeh"); + } + + + /** Get Property-value for vertical logo-placement property. */ + public String getLogoVPlacement() { + return getStringValue(LOGOPLACEMENTV_ATTR); + } + + + /** Set Property-value for vertical logo-placement property. */ + public void setLogoVPlacement(String place) { + setChoiceStringValue(LOGOPLACEMENTV_ATTR, place, "placev"); + } + + + public void setDisplayGrid(boolean displayGrid) { + setBooleanValue(DISPLAYGRID_ATTR, displayGrid); + } + + + public Boolean getDisplayGrid() { + return getBooleanValue(DISPLAYGRID_ATTR); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSettings.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,299 @@ +package de.intevation.flys.exports; + +import javax.xml.xpath.XPathConstants; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.state.DefaultSection; +import de.intevation.artifactdatabase.state.DefaultSettings; +import de.intevation.artifactdatabase.state.Section; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChartSettings extends DefaultSettings { + + private static final Logger logger = Logger.getLogger(ChartSettings.class); + + protected ChartSection chartSection; + protected LegendSection legendSection; + protected ExportSection exportSection; + protected Section axesSection; + + + public ChartSettings() { + super(); + + axesSection = new DefaultSection("axes"); + addSection(axesSection); + } + + + /** + * Sets the chart section. Old chart sections are removed. + * + * @param chartSection A new Section that stores chart specific attributes. + */ + public void setChartSection(ChartSection chartSection) { + ChartSection oldChartSection = getChartSection(); + + if (oldChartSection != null) { + removeSection(oldChartSection); + } + + this.chartSection = chartSection; + addSection(chartSection); + } + + + /** + * Returns the Section that stores chart specific attributes. + * + * @return the Section that stores chart specific attributes. + */ + public ChartSection getChartSection() { + return chartSection; + } + + + /** + * Sets the legend section. Old legend sections are removed. + * + * @param legendSection A new Section that stores legend specific + * attributes. + */ + public void setLegendSection(LegendSection legendSection) { + LegendSection oldLegendSection = getLegendSection(); + + if (oldLegendSection != null) { + removeSection(oldLegendSection); + } + + this.legendSection = legendSection; + addSection(legendSection); + } + + + /** + * Returns the Section that stores legend specific attributes. + * + * @return the Section that stores legend specific attributes. + */ + public LegendSection getLegendSection() { + return legendSection; + } + + + /** + * Sets the export section. Old export sections are removed. + * + * @param exportSection A new Section that stores export specific + * attributes. + */ + public void setExportSection(ExportSection exportSection) { + ExportSection oldExportSection = getExportSection(); + + if (oldExportSection != null) { + removeSection(oldExportSection); + } + + this.exportSection = exportSection; + addSection(exportSection); + } + + + /** + * Returns the Section that stores export specific attributes. + * + * @return the Section that stores export specific attributes. + */ + public ExportSection getExportSection() { + return exportSection; + } + + + /** + * Adds a Section for a new axis of the chart. + * + * @param axisSection The Section specific for a chart axis. + */ + public void addAxisSection(AxisSection axisSection) { + if (axisSection != null) { + axesSection.addSubsection(axisSection); + } + } + + + /** + * This method returns an AxisSection specified by <i>axisId</i> or null if + * no AxisSection is existing with identifier <i>axisId</i>. + * + * @param axisId The identifier of the wanted AxisSection. + * + * @return the AxisSection specified by <i>axisId</i> or null. + */ + public AxisSection getAxisSection(String axisId) { + for (int i = 0, n = axesSection.getSubsectionCount(); i < n; i++) { + AxisSection as = (AxisSection) axesSection.getSubsection(i); + String id = as.getIdentifier(); + + if (id != null && id.equals(axisId)) { + return as; + } + } + + return null; + } + + + /** + * Parses the settings from <i>settings</i>. The result is a new + * ChartSettings instance. + * + * @param settings A <i>settings</i> node. + * + * @return a new <i>ChartSettings</i> instance. + */ + public static ChartSettings parse(Node settings) { + if (settings == null) { + logger.warn("Tried to parse ChartSettings from empty Node!"); + return null; + } + + ChartSettings chartSettings = new ChartSettings(); + + parseAxes(chartSettings, settings); + parseChart(chartSettings, settings); + parseLegend(chartSettings, settings); + parseExport(chartSettings, settings); + + return chartSettings; + } + + + protected static void parseAxes(ChartSettings target, Node settings) { + NodeList axesList = (NodeList) XMLUtils.xpath( + settings, "axes/axis", XPathConstants.NODESET, null); + + int num = axesList != null ? axesList.getLength() : 0; + + if (num <= 0) { + logger.debug("No axis sections found."); + return; + } + + for (int i = 0; i < num; i++) { + parseAxis(target, axesList.item(i)); + } + } + + + protected static void parseAxis(ChartSettings target, Node axis) { + AxisSection section = new AxisSection(); + + String id = XMLUtils.xpathString(axis, "id", null); + String label = XMLUtils.xpathString(axis, "label", null); + String fSize = XMLUtils.xpathString(axis, "font-size", null); + String fixation = XMLUtils.xpathString(axis, "fixation", null); + String low = XMLUtils.xpathString(axis, "lower", null); + String up = XMLUtils.xpathString(axis, "upper", null); + + if (logger.isDebugEnabled()) { + logger.debug("Fount axis id: '" + id + "'"); + logger.debug("Fount axis label: '" + label + "'"); + logger.debug("Fount axis font size: '" + fSize + "'"); + logger.debug("Fount axis fixation: '" + fixation + "'"); + logger.debug("Fount axis lower: '" + low + "'"); + logger.debug("Fount axis upper: '" + up + "'"); + } + + section.setIdentifier(id); + section.setLabel(label); + section.setFontSize(Integer.parseInt(fSize.length() > 0 ? fSize : "-1")); + section.setFixed(Boolean.valueOf(fixation)); + section.setLowerRange(Double.parseDouble(low.length() > 0 ? low : "0")); + section.setUpperRange(Double.parseDouble(up.length() > 0 ? up : "0")); + + target.addAxisSection(section); + } + + + /** + * From document chart create ChartSection and populate it with attributes. + * Give this object to target as chartsection. + */ + protected static void parseChart(ChartSettings target, Node chart) { + ChartSection chartSection = new ChartSection(); + + String title = XMLUtils.xpathString(chart, "chart/title", null); + String sub = XMLUtils.xpathString(chart, "chart/subtitle", null); + String grid = XMLUtils.xpathString(chart, "chart/display-grid", null); + String logo = XMLUtils.xpathString(chart, "chart/display-logo", null); + String placeh = XMLUtils.xpathString(chart, "chart/logo-placeh", null); + String placev = XMLUtils.xpathString(chart, "chart/logo-placev", null); + + if (logger.isDebugEnabled()) { + logger.debug("Found chart title: '" + title + "'"); + logger.debug("Found chart subtitle: '" + sub + "'"); + logger.debug("Found chart grid: '" + grid + "'"); + logger.debug("Found chart logo: '" + logo + "'"); + logger.debug("Found chart logo placeh: '" + placeh + "'"); + logger.debug("Found chart logo placev: '" + placev + "'"); + } + + chartSection.setTitle(title); + chartSection.setSubtitle(sub); + chartSection.setDisplayGrid(Boolean.valueOf(grid)); + chartSection.setDisplayLogo(logo); + chartSection.setLogoHPlacement(placeh); + chartSection.setLogoVPlacement(placev); + + target.setChartSection(chartSection); + } + + + protected static void parseLegend(ChartSettings target, Node legend) { + LegendSection section = new LegendSection(); + + String vis = XMLUtils.xpathString(legend, "legend/visibility", null); + String fSize = XMLUtils.xpathString(legend, "legend/font-size", null); + String lthre = XMLUtils.xpathString(legend, "legend/aggregation-threshold", null); + + if (logger.isDebugEnabled()) { + logger.debug("Found legend visibility: '" + vis + "'"); + logger.debug("Found legend font size : '" + fSize + "'"); + logger.debug("Found legend aggregation threshold : '" + lthre + "'"); + } + + section.setVisibility(Boolean.valueOf(vis)); + section.setFontSize(Integer.valueOf(fSize.length() > 0 ? fSize : "-1")); + section.setAggregationThreshold(Integer.valueOf(lthre.length() >0 ? lthre : "-1")); + + target.setLegendSection(section); + } + + + protected static void parseExport(ChartSettings target, Node export) { + ExportSection section = new ExportSection(); + + String width = XMLUtils.xpathString(export, "export/width", null); + String height = XMLUtils.xpathString(export, "export/height", null); + + if (logger.isDebugEnabled()) { + logger.debug("Found export width : '" + width + "'"); + logger.debug("Found export height: '" + height + "'"); + } + + section.setWidth(Integer.valueOf(width.length() > 0 ? width : "-1")); + section.setHeight(Integer.valueOf(height.length() > 0 ? height : "-1")); + + target.setExportSection(section); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,45 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChoiceStringAttribute extends StringAttribute { + + /** Indicator which type of choice is dealt with. */ + protected String choiceType; + + + public ChoiceStringAttribute(String name, + String value, + boolean visible, + String choiceType) { + super(name, value, visible); + this.choiceType = choiceType; + } + + + /** + * Calls VisibleAttribute.toXML() and appends afterwards an attribute + * <i>type</i> with value <i>string</i>. + * + * @param parent The parent Node. + * + * @return the new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("type", "string"); + ele.setAttribute("choice", choiceType); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,220 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Date; +import java.text.DateFormat; +import java.util.Locale; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JRException; + +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WKmsJRDataSource; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ComputedDischargeCurveExporter extends AbstractExporter { + + /** The logger used in this exporter.*/ + private static Logger logger = + Logger.getLogger(ComputedDischargeCurveExporter.class); + + + public static final String CSV_W_HEADER = + "export.computed.discharge.curve.csv.header.w"; + + public static final String CSV_Q_HEADER = + "export.computed.discharge.curve.csv.header.q"; + + public static final String DEFAULT_CSV_W_HEADER = "W [NN + m]"; + public static final String DEFAULT_CSV_Q_HEADER = "Q [m\u00b3/s]"; + + public static final String PDF_HEADER_MODE = "export.computed.discharge.pdf.mode"; + public static final String JASPER_FILE = "export.computed.discharge.pdf.file"; + + protected List<WQKms> data; + + + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("ComputedDischargeCurveExporter.init"); + + super.init(request, out, context); + + this.data = new ArrayList<WQKms>(); + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WQKms []) { + data.addAll(Arrays.asList((WQKms [])d)); + } + } + } + + + protected void writeCSVData(CSVWriter writer) { + logger.info("ComputedDischargeCurveExporter.writeData"); + + writeCSVHeader(writer); + + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + double[] res = new double[3]; + + for (WQKms wqkms: data) { + int size = wqkms.size(); + + for (int i = 0; i < size; i++) { + res = wqkms.get(i, res); + + writer.writeNext(new String[] { + wf.format(res[0]), + qf.format(res[1]) + }); + } + } + } + + + protected void writeCSVHeader(CSVWriter writer) { + logger.debug("ComputedDischargeCurveExporter.writeCSVHeader"); + + writer.writeNext(new String[] { + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER) + }); + } + + + /** + * Returns the number formatter for W values. + * + * @return the number formatter for W values. + */ + protected NumberFormat getWFormatter() { + return Formatter.getComputedDischargeW(context); + } + + + /** + * Returns the number formatter for Q values. + * + * @return the number formatter for Q values. + */ + protected NumberFormat getQFormatter() { + return Formatter.getComputedDischargeQ(context); + } + + + @Override + protected void writePDF(OutputStream out) { + WKmsJRDataSource source = createJRData(); + + String jasperFile = Resources.getMsg( + context.getMeta(), + JASPER_FILE, + "/jasper/computed-discharge_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + } + + + protected WKmsJRDataSource createJRData() { + WKmsJRDataSource source = new WKmsJRDataSource(); + + addMetaData(source); + addWQData(source); + + return source; + } + + + protected void addMetaData(WKmsJRDataSource source) { + CallMeta meta = context.getMeta(); + + FLYSArtifact flys = (FLYSArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + double[] kms = FLYSUtils.getKmRange(flys); + source.addMetaData("range", String.valueOf(kms[0])); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "Computed Discharge")); + } + + protected void addWQData(WKmsJRDataSource source) { + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + double[] res = new double[3]; + + for (WQKms wqkms: data) { + int size = wqkms.size(); + + for (int i = 0; i < size; i++) { + res = wqkms.get(i, res); + + source.addData(new String[] { + "", // Empty, the WKmsJRDtasource stores km here. + wf.format(res[0]), + qf.format(res[1]) + }); + } + } + + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,263 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StickyAxisAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + + +/** + * An OutGenerator that generates discharge curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ComputedDischargeCurveGenerator +extends DischargeCurveGenerator +implements FacetTypes +{ + /** The logger used in this generator. */ + private static Logger logger = + Logger.getLogger(ComputedDischargeCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.computed.discharge.curve.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.computed.discharge.curve.subtitle"; + + public static final String I18N_YAXIS_LABEL = + "chart.computed.discharge.curve.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Abflusskurve"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]"; + public static final String I18N_MAINVALUES_Q_LABEL = "Q (Haupt- und Extremwerte)"; + public static final String I18N_MAINVALUES_W_LABEL = "W (Haupt- und Extremwerte)"; + + + /** Trivial Constructor. */ + public ComputedDischargeCurveGenerator () { + super(); + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + + @Override + protected String getDefaultChartSubtitle() { + double[] dist = getRange(); + + Object[] args = new Object[] { + getRiverName(), + dist[0] + }; + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + /** + * Process data, build up plot. + */ + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("ComputedDischargeCurveGenerator.doOut: " + name); + + if (name == null) { + logger.warn("Broken facet in computed discharge out generation."); + return; + } + + Facet facet = artifactFacet.getFacet(); + + if (name.equals(COMPUTED_DISCHARGE_Q)) { + doQOut((WQKms) artifactFacet.getData(context), artifactFacet, attr, visible); + } + else if (name.equals(STATIC_WQ)) { + doWQOut(artifactFacet.getData(context), artifactFacet, attr, visible); + } + else if (name.equals(STATIC_WQ_ANNOTATIONS)) { + doWQAnnotations( + artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) + || name.equals(MAINVALUES_Q) + || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) + || name.equals(MAINVALUES_W) + ) { + doAnnotations((FLYSAnnotation) + artifactFacet.getData(context), artifactFacet, attr, visible); + } + else if (name.equals(STATIC_WKMS_INTERPOL) || name.equals(HEIGHTMARKS_POINTS)) { + doWAnnotations( + artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(STATIC_WKMS)) { + doWAnnotations( + artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactFacet.getData(context), + artifactFacet, + attr, visible, YAXIS.W.idx); + } + else if (name.equals(DISCHARGE_CURVE)) { + doDischargeOut( + (WINFOArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else { + logger.warn("Unknown facet type for computed discharge: " + name); + return; + } + } + + + /** + * Add WQ Data to plot. + * @param wqkms data as double[][] + */ + protected void doWQOut( + Object wqkms, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + logger.debug("ComputedDischargeCurveGenerator: doWQOut"); + double [][] data = (double [][]) wqkms; + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data, true); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** + * Add Q-Series to plot. + * @param wqkms actual data + * @param theme theme to use. + */ + protected void doQOut( + WQKms wqkms, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + logger.debug("ComputedDischargeCurveGenerator: doWQOut"); + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + StyledSeriesBuilder.addPointsQW(series, wqkms); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** + * Add WQ-Annotations to plot. + * @param wqkms actual data + * @param theme theme to use. + */ + protected void doWQAnnotations( + Object wqkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + double [][] data = (double [][]) wqkms; + for (int i = 0; i< data[0].length; i++) { + // TODO we need linear interpolation? + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) data[0][i], StickyAxisAnnotation.SimpleAxis.X_AXIS)); + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + } + + doAnnotations(new FLYSAnnotation(aandf.getFacetDescription(), xy), + aandf, theme, visible); + } + + + /** + * Add W-Annotations to plot. + * @param wqkms actual data (double[][]). + * @param theme theme to use. + */ + protected void doWAnnotations( + Object wqkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + Facet facet = aandf.getFacet(); + + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + // Try to find them as WKms as well... + if (wqkms instanceof double[][]) { + logger.debug("its double[][] time, baby"); + double [][] data = (double [][]) wqkms; + // TODO Do we need interpolation? + for (int i = 0; i< data[0].length; i++) { + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + } + + doAnnotations(new FLYSAnnotation(facet.getDescription(), xy), + aandf, theme, visible); + } + else { + logger.debug("its wkms time, baby"); + WKms data = (WKms) wqkms; + // Assume its WKms. + double location = getRange()[0]; + double w = ((StaticWKmsArtifact) aandf.getArtifact()) + .getWAtKmLin(data, getRange()[0]); + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + + doAnnotations(new FLYSAnnotation(facet.getDescription(), xy), + aandf, theme, visible); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific computed + * discharge curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ComputedDischargeCurveInfoGenerator extends ChartInfoGenerator { + + public ComputedDischargeCurveInfoGenerator() { + super(new ComputedDischargeCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,433 @@ +package de.intevation.flys.exports; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Paint; +import java.awt.Stroke; +import java.text.NumberFormat; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYBoxAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifacts.DataProvider; +import de.intevation.flys.artifacts.geom.Lines; +import de.intevation.flys.artifacts.model.CrossSectionFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.HYKFactory; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.model.FastCrossSectionLine; +import de.intevation.flys.themes.LineStyle; +import de.intevation.flys.themes.TextStyle; +import de.intevation.flys.themes.ThemeAccess; +import de.intevation.flys.utils.Formatter; +import de.intevation.flys.utils.ThemeUtil; + + +/** + * An OutGenerator that generates cross section graphs. + */ +public class CrossSectionGenerator +extends LongitudinalSectionGenerator +implements FacetTypes +{ + /** The logger that is used in this generator. */ + private static Logger logger = + Logger.getLogger(CrossSectionGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.cross_section.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.cross_section.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.cross_section.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.cross_section.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Querprofildiagramm"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "Abstand [m]"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]"; + + + /** Trivial Constructor. */ + public CrossSectionGenerator() { + super(); + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return 1; + } + + /** Get identifier for this index. */ + @Override + public String getId(int idx) { + return "W"; + } + }; + } + + + /** + * Get localized chart title. + */ + @Override + public String getDefaultChartTitle() { + Object[] i18n_msg_args = new Object[] { + getRiverName() + }; + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, i18n_msg_args); + } + + + /** Always return default subtitle. */ + @Override + protected String getChartSubtitle() { + // XXX NOTE: overriding this method disables ChartSettings subtitle! + // The default implementation of this method in ChartGenerator returns + // the subtitle changed via the chart settings dialog. This method + // always returns the subtitle containing river and km, NEVER the + // ChartSettings subtitle! + return getDefaultChartSubtitle(); + } + + + /** Get Charts default subtitle. */ + @Override + protected String getDefaultChartSubtitle() { + List<DataProvider> providers = + context.getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA); + double km = 0d; + if (providers.size() > 0) { + FastCrossSectionLine csl = (FastCrossSectionLine) providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, + null, context); + km = csl == null ? -1 : csl.getKm(); + } + + Object[] args = new Object[] { + getRiverName(), + km + }; + + logger.debug("Locale: " + Resources.getLocale(context.getMeta())); + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + /** Get color for hyk zones by their type (which is the name). */ + protected Paint colorForHYKZone(String zoneName) { + if (zoneName.startsWith("R")) { + // Brownish. + return new Color(153, 60, 0); + } + else if (zoneName.startsWith("V")) { + // Greenish. + return new Color(0, 255, 0); + } + else if (zoneName.startsWith("B")) { + // Grayish. + return new Color(128, 128, 128); + } + else if (zoneName.startsWith("H")) { + // Blueish. + return new Color(0, 0, 255); + } + else { + // Default. + logger.debug("Unknown zone type found."); + return new Color(255, 0, 0); + } + } + + @Override + protected void addAnnotationsToRenderer(XYPlot plot) { + super.addAnnotationsToRenderer(plot); + + // Paints for the boxes/lines. + Stroke basicStroke = new BasicStroke(1.0f); + + Paint linePaint = new Color(255, 0,0,60); + Paint fillPaint = new Color(0, 255,0,60); + Paint tranPaint = new Color(0, 0,0, 0); + + // OPTMIMIZE: Pre-calculate positions + ChartArea area = new ChartArea( + plot.getDomainAxis(0).getRange(), + plot.getRangeAxis().getRange()); + + for(FLYSAnnotation fa : this.annotations) { + + // Access text styling, if any. + Document theme = fa.getTheme(); + TextStyle textStyle = null; + LineStyle lineStyle = null; + + // Get Themeing information and add legend item. + if (theme != null) { + ThemeAccess themeAccess = new ThemeAccess(theme); + textStyle = themeAccess.parseTextStyle(); + lineStyle = themeAccess.parseLineStyle(); + if (fa.getLabel() != null) { + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + lic.add(createLegendItem(theme, fa.getLabel())); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } + else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // Hyks. + for (HYKFactory.Zone zone: fa.getBoxes()) { + // For each zone, create a box to fill with color, a box to draw + // the lines and a text to display the type. + fillPaint = colorForHYKZone(zone.getName()); + + XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(), + zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint); + XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(), + zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint); + + XYTextAnnotation tex = new XYTextAnnotation(zone.getName(), + zone.getFrom() + (zone.getTo() - zone.getFrom()) / 1.0d, + area.ofGround(0.015f)); + if (textStyle != null) { + textStyle.apply(tex); + } + + plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND); + plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND); + plot.getRenderer().addAnnotation(tex, org.jfree.ui.Layer.BACKGROUND); + } + } + } + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + /** + * Let one facet do its job. + */ + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("CrossSectionGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + if (name.equals(CROSS_SECTION)) { + doCrossSectionOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (name.equals(CROSS_SECTION_WATER_LINE)) { + doCrossSectionWaterLineOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.AREA(name)) { + doArea(artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(HYK)) { + doHyk(artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.MANUALLINE(name)) { + doCrossSectionWaterLineOut( + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactFacet.getData(context), + artifactFacet, + attr, visible, YAXIS.W.idx); + } + else { + logger.warn("CrossSection.doOut: Unknown facet name: " + name); + return; + } + } + + + /** Look up the axis identifier for a given facet type. */ + @Override + public int axisIdxForFacet(String facetName) { + // TODO Where to add thid axis too. + return 0; + } + + + /** + * Do cross sections waterline out. + * + * @param seriesName name of the data (line) to display in legend. + * @param theme Theme for the data series. + */ + protected void doCrossSectionWaterLineOut( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doCrossSectionWaterLineOut"); + + Lines.LineData lines = (Lines.LineData) o; + // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. + StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); + + if (!ThemeUtil.parseShowLineLabel(theme)) { + series.setLabel(""); + } + if (ThemeUtil.parseShowWidth(theme)) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + String labelAdd = "b=" + nf.format(lines.width) + "m"; + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + if (ThemeUtil.parseShowLevel(theme) && lines.points.length >0 + && lines.points[1].length > 0) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + String labelAdd = "W=" + nf.format(lines.points[1][0]) + "NN+m"; + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + if (ThemeUtil.parseShowMiddleHeight(theme) && lines.width != 0) { + NumberFormat nf = Formatter.getMeterFormat(this.context); + String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m"; + // : " + lines.area + "/" + lines.width); + if (series.getLabel().length() == 0) { + series.setLabel(labelAdd); + } + else { + series.setLabel(series.getLabel() + ", " + labelAdd); + } + } + + StyledSeriesBuilder.addPoints(series, lines.points, false); + + addAxisSeries(series, 0, visible); + } + + + /** Add HYK-Annotations (colorize and label some areas, draw lines. */ + protected void doHyk( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doHyk"); + + List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>) o; + + if (zones == null || zones.isEmpty()) { + logger.warn("CrossSectionGenerator.doHYK: empty zone list received."); + return; + } + + // Actual Styling is done in XYChartGenerator. + if (visible) { + addAnnotations(new FLYSAnnotation(seriesName, null, zones, theme)); + } + } + + + /** + * Do cross sections out. + * + * @param seriesName name of the data (line) to display in legend. + * @param theme Theme for the data series. + */ + protected void doCrossSectionOut( + Object o, + String seriesName, + Document theme, + boolean visible + ) { + logger.debug("CrossSectionGenerator.doCrossSectionOut"); + + XYSeries series = new StyledXYSeries(seriesName, theme); + + StyledSeriesBuilder.addPoints(series, (double [][]) o, false); + + addAxisSeries(series, 0, visible); + } + + + /** + * Creates a new <i>ChartSection</i>. + * + * Overridden to prevent inclusion of subtitle. + * + * @return a new <i>ChartSection</i>. + */ + @Override + protected ChartSection buildChartSection() { + ChartSection chartSection = new ChartSection(); + chartSection.setTitle(getChartTitle()); + chartSection.setDisplayGrid(isGridVisible()); + chartSection.setDisplayLogo(showLogo()); + chartSection.setLogoVPlacement(logoVPlace()); + chartSection.setLogoHPlacement(logoHPlace()); + return chartSection; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,14 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific cross + * sections. + */ +public class CrossSectionInfoGenerator extends ChartInfoGenerator { + + public CrossSectionInfoGenerator() { + super(new CrossSectionGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,187 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; +import de.intevation.flys.utils.FLYSUtils; + +import org.apache.log4j.Logger; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.Range; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + + +/** + * An OutGenerator that generates discharge curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DischargeCurveGenerator +extends XYChartGenerator +implements FacetTypes { + + public static enum YAXIS { + W(0); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** The logger used in this generator. */ + private static Logger logger = + Logger.getLogger(DischargeCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.discharge.curve.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.discharge.curve.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.discharge.curve.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.discharge.curve.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Abflusskurven"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "W [cm]"; + + + public DischargeCurveGenerator() { + super(); + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + /** + * Returns always null to suppress subtitles. + */ + @Override + protected String getDefaultChartTitle() { + return null; + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + /* TODO is this one really needed? */ + @Override + protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + boolean zoomin = super.zoom(plot, axis, bounds, x); + + if (!zoomin) { + axis.setLowerBound(0d); + } + + return zoomin; + } + + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document theme, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + logger.debug("DischargeCurveGenerator.doOut: " + name); + + if (name.equals(DISCHARGE_CURVE)) { + doDischargeOut( + (WINFOArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) + || name.equals(MAINVALUES_Q) + || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) + || name.equals(MAINVALUES_W)) + { + doAnnotations((FLYSAnnotation) artifactFacet.getData(context), + artifactFacet, theme, visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactFacet.getData(context), + artifactFacet, + theme, visible, YAXIS.W.idx); + } + else { + logger.warn("DischargeCurveGenerator.doOut: Unknown facet name: " + name); + return; + } + } + + + /** + * Add series with discharge curve to diagram. + */ + protected void doDischargeOut( + WINFOArtifact artifact, + Object o, + String description, + Document theme, + boolean visible) + { + WQKms wqkms = (WQKms) o; + + String gaugeName = wqkms.getName(); + + River river = FLYSUtils.getRiver(artifact); + + if (river == null) { + logger.debug("no river found"); + return; + } + + Gauge gauge = river.determineGaugeByName(gaugeName); + + if (gauge == null) { + logger.debug("no gauge found"); + return; + } + + XYSeries series = new StyledXYSeries(description, theme); + + StyledSeriesBuilder.addPointsQW(series, wqkms); + + addAxisSeries(series, YAXIS.W.idx, visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,16 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific discharge + * curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DischargeCurveInfoGenerator extends ChartInfoGenerator { + + public DischargeCurveInfoGenerator() { + super(new DischargeCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.exports; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; + +import java.text.NumberFormat; + +import org.apache.log4j.Logger; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DischargeLongitudinalSectionExporter extends WaterlevelExporter { + + /** The logger used in this exporter.*/ + private static Logger logger = + Logger.getLogger(DischargeLongitudinalSectionExporter.class); + + + public static final String CSV_KM_HEADER = + "export.discharge.longitudinal.section.csv.header.km"; + + public static final String CSV_W_HEADER = + "export.discharge.longitudinal.section.csv.header.w"; + + public static final String CSV_CW_HEADER = + "export.discharge.longitudinal.section.csv.header.cw"; + + public static final String CSV_Q_HEADER = + "export.discharge.longitudinal.section.csv.header.q"; + + public static final String DEFAULT_CSV_KM_HEADER = "Fluss-Km"; + public static final String DEFAULT_CSV_W_HEADER = "W [NN + m]"; + public static final String DEFAULT_CSV_CW_HEADER = "W korr."; + public static final String DEFAULT_CSV_Q_HEADER = "Q [m\u00b3/s]"; + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WQKms []) { + data.add((WQKms [])d); + } + } + } + + + @Override + protected void writeCSVHeader( + CSVWriter writer, + boolean atGauge, + boolean isQ + ) { + logger.info("WaterlevelExporter.writeCSVHeader"); + + writer.writeNext(new String[] { + msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_CW_HEADER, DEFAULT_CSV_CW_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER) + }); + } + + + protected void wQKms2CSV( + CSVWriter writer, + WQKms wqkms, + boolean atGauge, + boolean isQ, + boolean isRange + ) { + logger.debug("WaterlevelExporter.wQKms2CSV"); + + int size = wqkms.size(); + double[] result = new double[4]; + + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + for (int i = 0; i < size; i ++) { + result = wqkms.get(i, result); + + String wc = ""; + if (wqkms instanceof WQCKms) { + wc = wf.format(result[3]); + } + + writer.writeNext(new String[] { + kmf.format(result[2]), + wf.format(result[0]), + wc, + qf.format(result[1]) + }); + } + } + + + @Override + protected void addWSTColumn(WstWriter writer, WQKms wqkms) { + String name = wqkms.getName(); + + // is it a W or a Q mode? + int wIdx = name.indexOf("W"); + int qIdx = name.indexOf("Q"); + + String wq = null; + if (wIdx >= 0) { + wq = "W"; + } + else if (qIdx >= 0) { + wq = "Q"; + } + + // we just want to display the first W or Q value in the WST + int start = name.indexOf("("); + int end = name.indexOf(")"); + + String tmp = name.substring(start+1, end); + String[] values = tmp.split(";"); + + String column = wq + "=" + values[0]; + + writer.addColumn(column); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,131 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +import org.jfree.data.xy.XYSeries; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WKms; + +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; + + + +/** + * An OutGenerator that generates discharge longitudinal section curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DischargeLongitudinalSectionGenerator +extends LongitudinalSectionGenerator +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(DischargeLongitudinalSectionGenerator.class); + + + public DischargeLongitudinalSectionGenerator() { + super(); + } + + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + logger.debug("DischargeLongitudinalSectionGenerator.doOut"); + + String name = artifactFacet.getFacetName(); + + if (name == null) { + return; + } + + Facet facet = artifactFacet.getFacet(); + + if (IS.WQ_KM(name)) { + doWOut( + (WQKms) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(DISCHARGE_LONGITUDINAL_Q)) { + doQOut( + (WQKms) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(DISCHARGE_LONGITUDINAL_C)) { + doCorrectedWOut( + (WQCKms) artifactFacet.getData(context), + facet, + attr, + visible); + } + else if (IS.W_KM(name)) { + doWOut( + (WKms) artifactFacet.getData(context), + artifactFacet, + attr, visible); + } + else if (name.equals(LONGITUDINAL_ANNOTATION)) { + doAnnotations((FLYSAnnotation) artifactFacet.getData(context), + artifactFacet, attr, visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactFacet.getData(context), + artifactFacet, + attr, visible, YAXIS.W.idx); + } + else { + logger.warn("Unknown facet name: " + name); + } + } + + + /** + * Adds a new series for the corrected W curve. + * + * @param wqckms The object that contains the corrected W values. + * @param theme The theme that contains styling information. + */ + protected void doCorrectedWOut( + WQCKms wqckms, + Facet facet, + Document theme, + boolean visible + ) { + logger.debug("DischargeLongitudinalSectionGenerator.doCorrectedWOut"); + + int size = wqckms.size(); + + if (size > 0) { + XYSeries series = new StyledXYSeries( + facet.getDescription(), + theme); + + for (int i = 0; i < size; i++) { + series.add(wqckms.getKm(i), wqckms.getC(i)); + } + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + if (wqckms.guessWaterIncreasing()) { + setInverted(true); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific discharge + * longitudinal section curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DischargeLongitudinalSectionInfoGenerator +extends ChartInfoGenerator +{ + public DischargeLongitudinalSectionInfoGenerator() { + super(new DischargeLongitudinalSectionGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DoubleAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,37 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DoubleAttribute extends VisibleAttribute { + + + public DoubleAttribute(String name, double value, boolean visible) { + super(name, value, visible); + } + + + /** + * Calls VisibleAttribute.toXML() and appends afterwards an attribute + * <i>type</i> with value <i>double</i>. + * + * @param parent The parent Node. + * + * @return the new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("type", "double"); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,261 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Date; +import java.text.DateFormat; +import java.util.Locale; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JRException; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.WQDay; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WKmsJRDataSource; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DurationCurveExporter extends AbstractExporter { + + /** The logger used in this exporter. */ + private static Logger logger = Logger.getLogger(DurationCurveExporter.class); + + + public static final String CSV_DURATION_HEADER = + "export.duration.curve.csv.header.duration"; + + public static final String CSV_W_HEADER = + "export.duration.curve.csv.header.w"; + + public static final String CSV_Q_HEADER = + "export.duration.curve.csv.header.q"; + + public static final String DEFAULT_CSV_DURATION_HEADER = "D [Tagen]"; + public static final String DEFAULT_CSV_W_HEADER = "W [NN + m]"; + public static final String DEFAULT_CSV_Q_HEADER = "Q [m\u00b3/s]"; + + public static final String PDF_HEADER_MODE = "export.duration.pdf.mode"; + public static final String JASPER_FILE = "export.duration.pdf.file"; + + /** The storage that contains all WQKms objects for the different facets. */ + protected List<WQDay> data; + + + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("DurationCurveExporter.init"); + + super.init(request, out, context); + + this.data = new ArrayList<WQDay>(); + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WQDay) { + data.add((WQDay)d); + } + } + } + + + protected void writeCSVData(CSVWriter writer) { + logger.info("DurationCurveExporter.writeData"); + + writeCSVHeader(writer); + + for (WQDay wqday: data) { + wQDay2CSV(writer, wqday); + } + } + + + protected void writeCSVHeader(CSVWriter writer) { + logger.info("DurationCurveExporter.writeCSVHeader"); + + writer.writeNext(new String[] { + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), + msg(CSV_DURATION_HEADER, DEFAULT_CSV_DURATION_HEADER) + }); + } + + + protected void wQDay2CSV(CSVWriter writer, WQDay wqday) { + logger.debug("DurationCurveExporter.wQDay2CSV"); + + int size = wqday.size(); + + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + NumberFormat df = getDFormatter(); + + if (wqday.isIncreasing()) { + for (int i = size-1; i >= 0; i --) { + writer.writeNext(new String[] { + wf.format(wqday.getW(i)), + qf.format(wqday.getQ(i)), + df.format(wqday.getDay(i)) + }); + } + } + else { + for (int i = 0; i < size; i ++) { + writer.writeNext(new String[] { + wf.format(wqday.getW(i)), + qf.format(wqday.getQ(i)), + df.format(wqday.getDay(i)) + }); + } + } + } + + + /** + * Returns the number formatter for W values. + * + * @return the number formatter for W values. + */ + @Override + protected NumberFormat getWFormatter() { + return Formatter.getDurationW(context); + } + + + /** + * Returns the number formatter for Q values. + * + * @return the number formatter for Q values. + */ + @Override + protected NumberFormat getQFormatter() { + return Formatter.getDurationQ(context); + } + + + /** + * Returns the number formatter for duration values. + * + * @return the number formatter for duration values. + */ + protected NumberFormat getDFormatter() { + return Formatter.getDurationD(context); + } + + + @Override + protected void writePDF(OutputStream out) { + WKmsJRDataSource source = createJRData(); + + String jasperFile = Resources.getMsg( + context.getMeta(), + JASPER_FILE, + "/jasper/duration_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + } + + protected WKmsJRDataSource createJRData() { + WKmsJRDataSource source = new WKmsJRDataSource(); + + addMetaData(source); + for (WQDay wqday: data) { + addWQDayData(source, wqday); + } + + return source; + } + + + protected void addMetaData(WKmsJRDataSource source) { + CallMeta meta = context.getMeta(); + + FLYSArtifact flys = (FLYSArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + double[] kms = FLYSUtils.getKmRange(flys); + source.addMetaData("range", String.valueOf(kms[0])); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "Duration")); + } + + protected void addWQDayData(WKmsJRDataSource source, WQDay wqday) { + int size = wqday.size(); + + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + NumberFormat df = getDFormatter(); + + if (wqday.isIncreasing()) { + for (int i = size-1; i >= 0; i --) { + source.addData(new String[] { + "", + wf.format(wqday.getW(i)), + qf.format(wqday.getQ(i)), + "", "", "", + df.format(wqday.getDay(i)) + }); + } + } + else { + for (int i = 0; i < size; i ++) { + source.addData(new String[] { + "", + wf.format(wqday.getW(i)), + qf.format(wqday.getQ(i)), + "", "", "", + df.format(wqday.getDay(i)) + }); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,313 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WQDay; +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; + +import java.awt.Font; +import java.awt.geom.Point2D; + +import org.apache.log4j.Logger; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.Range; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + + +/** + * An OutGenerator that generates duration curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DurationCurveGenerator +extends XYChartGenerator +implements FacetTypes +{ + public static enum YAXIS { + W(0), + Q(1); + public int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** Local logger. */ + private static Logger logger = + Logger.getLogger(DurationCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.duration.curve.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.duration.curve.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.duration.curve.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.duration.curve.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = + "Dauerlinie"; + + public static final String I18N_XAXIS_LABEL_DEFAULT = + "Unterschreitungsdauer [Tage]"; + + public static final String I18N_YAXIS_LABEL_DEFAULT = + "W [NN + m]"; + + + public DurationCurveGenerator() { + super(); + } + + + /** + * Create Axis for given index. + * @return axis with according internationalized label. + */ + @Override + protected NumberAxis createYAxis(int index) { + Font labelFont = new Font("Tahoma", Font.BOLD, 14); + String label = getYAxisLabel(index); + + NumberAxis axis = createNumberAxis(index, label); + if (index == YAXIS.W.idx) { + axis.setAutoRangeIncludesZero(false); + } + axis.setLabelFont(labelFont); + return axis; + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + + @Override + protected String getDefaultChartSubtitle() { + double[] dist = getRange(); + + Object[] args = new Object[] { + getRiverName(), + dist[0] + }; + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + + @Override + protected String getDefaultYAxisLabel(int index) { + String label = "default"; + if (index == YAXIS.W.idx) { + label = msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + else if (index == YAXIS.Q.idx) { + // TODO i18n for this label + label = "Q [m\u00b3/s]"; + //label = msg(get2YAxisLabelKey(), get2YAxisDefaultLabel()); + } + + return label; + } + + + @Override + protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + boolean zoomin = super.zoom(plot, axis, bounds, x); + + if (!zoomin) { + axis.setLowerBound(0d); + } + + axis.setUpperBound(364); + + return zoomin; + } + + + /** + * This method overrides the method in the parent class to set the lower + * bounds of the Q axis to 0. This axis should never display negative + * values on its own. + */ + @Override + protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + boolean zoomin = super.zoom(plot, axis, bounds, x); + + if (!zoomin && axis instanceof IdentifiableNumberAxis) { + String id = ((IdentifiableNumberAxis) axis).getId(); + + if (YAXIS.Q.toString().equals(id)) { + axis.setLowerBound(0d); + } + } + + return zoomin; + } + + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("DurationCurveGenerator.doOut: " + name); + + if (name == null || name.length() == 0) { + logger.error("No facet given. Cannot create dataset."); + return; + } + + if (name.equals(DURATION_W)) { + doWOut( + (WQDay) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(DURATION_Q)) { + doQOut( + (WQDay) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(DURATION_MAINVALUES_Q) + || name.equals(MAINVALUES_Q) + || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) + || name.equals(MAINVALUES_W) + ) { + doAnnotations( + (FLYSAnnotation) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (name.equals(RELATIVE_POINT)) { + doPointOut((Point2D) artifactFacet.getData(context), + artifactFacet, + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints( + artifactFacet.getData(context), + artifactFacet, + attr, visible, YAXIS.W.idx); + } + else { + logger.warn("Unknown facet name: " + name); + return; + } + } + + + /** + * Creates the series for a duration curve's W facet. + * + * @param wqdays The WQDay store that contains the Ws. + * @param theme + */ + protected void doWOut( + WQDay wqdays, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + logger.debug("DurationCurveGenerator.doWOut"); + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + + int size = wqdays.size(); + for (int i = 0; i < size; i++) { + int day = wqdays.getDay(i); + double w = wqdays.getW(i); + + series.add(day, w); + } + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + protected void doPointOut( + Point2D point, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ){ + logger.debug("DurationCurveGenerator.doPointOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + series.add(point.getX(), point.getY()); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** + * Creates the series for a duration curve's Q facet. + * + * @param wqdays The WQDay store that contains the Qs. + * @param theme + */ + protected void doQOut( + WQDay wqdays, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + logger.debug("DurationCurveGenerator.doQOut"); + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + + int size = wqdays.size(); + for (int i = 0; i < size; i++) { + int day = wqdays.getDay(i); + double q = wqdays.getQ(i); + + series.add(day, q); + } + + addAxisSeries(series, YAXIS.Q.idx, visible); + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + // MainValue-Annotations should be visualized by a line that goes to the curve itself. +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific duration + * curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DurationCurveInfoGenerator +extends ChartInfoGenerator +{ + public DurationCurveInfoGenerator() { + super(new DurationCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/EmptySettings.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,78 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifactdatabase.state.Section; + + +/** + * An implementation of <i>Settings</i> that doesn't take new <i>Section</i>s + * and that always creates an empty <b>settings</b> DOM node in its + * <i>toXML()</i> operation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class EmptySettings implements Settings { + + public EmptySettings() { + } + + + /** + * This method has no function. It is not implemented! + * + * @param section A Section. + */ + @Override + public void addSection(Section section) { + // do nothing + } + + + /** + * Always returns 0. + * + * @return 0. + */ + @Override + public int getSectionCount() { + return 0; + } + + + /** + * This method always returns null. It is not implemented! + * + * @param pos A position. + * + * @return null. + */ + @Override + public Section getSection(int pos) { + return null; + } + + + /** + * This method has no function. It is not implemented! + */ + @Override + public void removeSection(Section section) { + // do nothing + } + + + /** + * This method creates an empty <i>settings</i> DOM node. + * + * @param parent A parent DOM node. + */ + @Override + public void toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + parent.appendChild(owner.createElement("settings")); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ExportSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,46 @@ +package de.intevation.flys.exports; + + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ExportSection extends TypeSection { + + public static final String WIDTH_ATTR = "width"; + public static final String HEIGHT_ATTR = "height"; + + + public ExportSection() { + super("export"); + } + + + public void setWidth(int width) { + if (width <= 0) { + return; + } + + setIntegerValue(WIDTH_ATTR, width); + } + + + public Integer getWidth() { + return getIntegerValue(WIDTH_ATTR); + } + + + public void setHeight(int height) { + if (height <= 0) { + return; + } + + setIntegerValue(HEIGHT_ATTR, height); + } + + + public Integer getHeight() { + return getIntegerValue(HEIGHT_ATTR); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/FlowVelocityExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,127 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.FlowVelocityData; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FlowVelocityExporter extends AbstractExporter { + + private static final Logger logger = + Logger.getLogger(FlowVelocityExporter.class); + + + public static final String CSV_KM = + "export.flow_velocity.csv.header.km"; + + public static final String CSV_V_TOTAL = + "export.flow_velocity.csv.header.v_total"; + + public static final String CSV_V_MAIN = + "export.flow_velocity.csv.header.v_main"; + + public static final String CSV_TAU_MAIN = + "export.flow_velocity.csv.header.tau_main"; + + public static final String CSV_Q = + "export.flow_velocity.csv.header.q"; + + public static final String CSV_LOCATIONS = + "export.flow_velocity.csv.header.locations"; + + + protected List<FlowVelocityData[]> data; + + + public void init(Document request, OutputStream out, CallContext cc) { + super.init(request, out, cc); + data = new ArrayList<FlowVelocityData[]>(); + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult) d).getData(); + + if (d instanceof FlowVelocityData[]) { + logger.debug("Add new data of type FlowVelocityData"); + data.add((FlowVelocityData[]) d); + } + } + } + + + @Override + protected void writeCSVData(CSVWriter writer) { + logger.info("FlowVelocityExporter.writeCSVData"); + logger.debug("CSV gets " + data.size() + " FlowVelocityData objects."); + + writeCSVHeader(writer); + + for (FlowVelocityData[] d: data) { + data2CSV(writer, d); + } + } + + + protected void writeCSVHeader(CSVWriter writer) { + writer.writeNext(new String[] { + msg(CSV_KM, CSV_KM), + msg(CSV_V_TOTAL, CSV_V_TOTAL), + msg(CSV_V_MAIN, CSV_V_MAIN), + msg(CSV_TAU_MAIN, CSV_TAU_MAIN), + msg(CSV_Q, CSV_Q), + msg(CSV_LOCATIONS, CSV_LOCATIONS) + }); + } + + + protected void data2CSV(CSVWriter writer, FlowVelocityData[] fData) { + logger.debug("Add next FlowVelocityData to CSV"); + + FLYSArtifact flys = (FLYSArtifact) master; + + for (FlowVelocityData data: fData) { + for (int i = 0, n = data.size(); i < n; i++) { + NumberFormat kmF = Formatter.getFlowVelocityKM(context); + NumberFormat valF = Formatter.getFlowVelocityValues(context); + NumberFormat qF = Formatter.getFlowVelocityQ(context); + + writer.writeNext(new String[] { + kmF.format(data.getKM(i)), + valF.format(data.getVMain(i)), + valF.format(data.getVTotal(i)), + valF.format(data.getTauMain(i)), + qF.format(data.getQ(i)) + "=" + data.getZone(), + FLYSUtils.getLocationDescription(flys, data.getKM(i)), + }); + } + } + } + + + @Override + protected void writePDF(OutputStream out) { + logger.error("TODO: Implement FlowVelocityExporter.writePDF"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/FlowVelocityGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,348 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +import org.jfree.data.xy.XYSeries; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.FlowVelocityData; + +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; + +import de.intevation.flys.utils.FLYSUtils; + + + +/** + * An OutGenerator that generates flow velocity curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FlowVelocityGenerator +extends XYChartGenerator +implements FacetTypes +{ + public enum YAXIS { + V(0), + T(1); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(FlowVelocityGenerator.class); + + /** Key to look up internationalized String for annotations label. */ + public static final String I18N_ANNOTATIONS_LABEL = + "chart.flow_velocity.annotations.label"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * titles. + */ + public static final String I18N_CHART_TITLE = + "chart.flow_velocity.section.title"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * subtitles. + */ + public static final String I18N_CHART_SUBTITLE = + "chart.flow_velocity.section.subtitle"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * short subtitles. + */ + public static final String I18N_CHART_SHORT_SUBTITLE = + "chart.flow_velocity.section.shortsubtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.flow_velocity.section.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.flow_velocity.section.yaxis.label"; + + public static final String I18N_2YAXIS_LABEL = + "chart.flow_velocity.section.yaxis.second.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Geschwindigkeit- und Schubspannung"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "km"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "Geschwindigkeit v [m/s]"; + public static final String I18N_2YAXIS_LABEL_DEFAULT = "Schubspannung Tau [N]"; + + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + /** + * Returns the default title for this chart. + * + * @return the default title for this chart. + */ + @Override + public String getDefaultChartTitle() { + Object[] args = new Object[] { + getRiverName() + }; + + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, args); + } + + + /** + * Get internationalized label for the x axis. + */ + @Override + protected String getDefaultXAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg( + I18N_XAXIS_LABEL, + I18N_XAXIS_LABEL_DEFAULT, + new Object[] { FLYSUtils.getRiver(flys).getName() }); + } + + + @Override + protected String getDefaultYAxisLabel(int index) { + String label = "default"; + + if (index == YAXIS.V.idx) { + label = getVAxisLabel(); + } + else if (index == YAXIS.T.idx) { + label = getTAxisLabel(); + } + + return label; + } + + + /** + * Get internationalized label for the y axis. + */ + protected String getVAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + /** + * Get internationalized label for the y axis. + */ + protected String getTAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg(I18N_2YAXIS_LABEL, I18N_2YAXIS_LABEL_DEFAULT); + } + + + /** + * Produce output. + * @param artifactAndFacet current facet. + * @param attr theme for facet + * @param visible Whether this facets data is actually visible or not. + */ + public void doOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + String name = artifactAndFacet.getFacetName(); + + logger.debug("FlowVelocityGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + Facet facet = artifactAndFacet.getFacet(); + + if (facet == null) { + return; + } + + if (name.equals(FLOW_VELOCITY_MAINCHANNEL)) { + doMainChannelOut( + (FlowVelocityData) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(FLOW_VELOCITY_TOTALCHANNEL)) { + doTotalChannelOut( + (FlowVelocityData) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(FLOW_VELOCITY_TAU)) { + doTauOut( + (FlowVelocityData) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(FLOW_VELOCITY_ANNOTATION)) { + doAnnotations( + (FLYSAnnotation) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.AREA(name)) { + doArea( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible, + YAXIS.V.idx); + } + else { + logger.warn("Unknown facet name: " + name); + return; + } + } + + + /** + * Process the output for W facets in a longitudinal section curve. + * + * @param data A FlowVelocityData object + * @param aandf The facet. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + */ + protected void doMainChannelOut( + FlowVelocityData data, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("FlowVelocityGenerator.doMainChannelOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getMainChannelPoints(), true); + + addAxisSeries(series, YAXIS.V.idx, visible); + } + + + /** + * Add items to dataseries which describes the differences. + */ + protected void doTotalChannelOut( + FlowVelocityData data, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("FlowVelocityGenerator.doTotalChannelOut"); + + if (data == null) { + logger.warn("No data to add to FlowVelocity chart."); + return; + } + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getTotalChannelPoints(), true); + + addAxisSeries(series, YAXIS.V.idx, visible); + } + + + + /** + * @param data A FlowVelocityData object + * @param aandf The facet. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + */ + protected void doTauOut( + FlowVelocityData data, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("FlowVelocityGenerator.doTauOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getTauPoints(), true); + + addAxisSeries(series, YAXIS.T.idx, visible); + } + + + /** Look up the axis identifier for a given facet type. */ + public int axisIdxForFacet(String facetName) { + if (FacetTypes.IS.V(facetName)) { + return YAXIS.V.idx; + } + else if (FacetTypes.IS.T(facetName)) { + return YAXIS.T.idx; + } + else { + logger.warn("Could not find axis for facet " + facetName); + return YAXIS.V.idx; + } + } + + + /** + * Do Area out. + * @param theme styling information. + * @param visible whether or not visible. + */ + protected void doArea( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("FlowVelocityGenerator.doArea"); + logger.warn("TODO: Implement FlowVelocityGenerator.doArea"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/FlowVelocityInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * flow velocity curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class FlowVelocityInfoGenerator +extends ChartInfoGenerator +{ + public FlowVelocityInfoGenerator() { + super(new FlowVelocityGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,242 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Locale; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JRException; + +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.Timerange; +import de.intevation.flys.artifacts.model.WQTimerange; +import de.intevation.flys.artifacts.model.WQTJRDataSource; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeCurveExporter extends AbstractExporter { + + private static final Logger logger = + Logger.getLogger(HistoricalDischargeCurveExporter.class); + + + public static final String CSV_TIMERANGE_HEADER = + "export.historical.discharge.csv.header.timerange"; + + public static final String CSV_WATERLEVEL_HEADER = + "export.historical.discharge.csv.header.waterlevel"; + + public static final String CSV_DISCHARGE_HEADER = + "export.historical.discharge.csv.header.discharge"; + + public static final String CSV_DIFF_HEADER = + "export.historical.discharge.csv.header.diff"; + + public static final String CSV_GAUGENAME_HEADER = + "export.historical.discharge.csv.header.gaugename"; + + public static final String PDF_HEADER_MODE = + "export.historical.discharge.pdf.mode"; + + public static final String JASPER_FILE = + "export.historical.discharge.pdf.file"; + + protected List<WQTimerange[]> data; + + + public void init(Document request, OutputStream out, CallContext cc) { + super.init(request, out, cc); + + data = new ArrayList<WQTimerange[]>(); + } + + + @Override + protected void addData(Object d) { + logger.debug("Add data of class: " + d.getClass()); + + if (d instanceof CalculationResult) { + d = ((CalculationResult) d).getData(); + + logger.debug("Internal data of CalculationResult: " + d.getClass()); + + if (d instanceof WQTimerange[]) { + logger.debug("Add new data of type WQTimerange"); + data.add((WQTimerange[]) d); + } + } + } + + + @Override + protected void writeCSVData(CSVWriter writer) { + logger.info("HistoricalDischargeCurveExporter.writeCSVData"); + logger.debug("CSV gets " + data.size() + " WQTimerange[] objects."); + + writeCSVHeader(writer); + + for (WQTimerange[] arr: data) { + for (WQTimerange wqt: arr) { + wqt2CSV(writer, wqt); + } + } + } + + + @Override + protected void writePDF(OutputStream out) { + WQTJRDataSource source = createJRData(); + + String jasperFile = Resources.getMsg( + context.getMeta(), + JASPER_FILE, + "/jasper/historical-discharge_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + + } + + + protected void writeCSVHeader(CSVWriter writer) { + writer.writeNext(new String[] { + msg(CSV_TIMERANGE_HEADER, CSV_TIMERANGE_HEADER), + msg(CSV_WATERLEVEL_HEADER, CSV_WATERLEVEL_HEADER), + msg(CSV_DISCHARGE_HEADER, CSV_DISCHARGE_HEADER), + msg(CSV_DIFF_HEADER, CSV_DIFF_HEADER), + msg(CSV_GAUGENAME_HEADER, CSV_GAUGENAME_HEADER) + }); + } + + + protected void wqt2CSV(CSVWriter writer, WQTimerange wqt) { + logger.debug("Add next WQTimerange to CSV"); + + DateFormat df = Formatter.getMediumDateFormat(context); + NumberFormat wf = Formatter.getHistoricalDischargeW(context); + NumberFormat qf = Formatter.getHistoricalDischargeQ(context); + + double[] wq = new double[3]; + + String gaugeName = getReferenceGaugename(); + + for (int i = 0, n = wqt.size(); i < n; i++) { + Timerange tr = wqt.getTimerange(i); + Date start = new Date(tr.getStart()); + Date end = new Date(tr.getEnd()); + + wqt.get(i, wq); + + writer.writeNext(new String[] { + df.format(start) + " - " + df.format(end), + wf.format(wq[0]), + qf.format(wq[1]), + qf.format(wq[2]), + gaugeName + }); + } + } + + + protected WQTJRDataSource createJRData() { + WQTJRDataSource source = new WQTJRDataSource(); + + addMetaData(source); + for (WQTimerange[] arr: data) { + for (WQTimerange wqt: arr) { + addWQTData(source, wqt); + } + } + + return source; + } + + + protected void addMetaData(WQTJRDataSource source) { + CallMeta meta = context.getMeta(); + + FLYSArtifact flys = (FLYSArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "Historical Discharge")); + } + + + protected void addWQTData(WQTJRDataSource source, WQTimerange wqt) { + DateFormat df = Formatter.getShortDateFormat(context); + NumberFormat wf = Formatter.getHistoricalDischargeW(context); + NumberFormat qf = Formatter.getHistoricalDischargeQ(context); + + double[] wq = new double[3]; + + String gaugeName = getReferenceGaugename(); + + for (int i = 0, n = wqt.size(); i < n; i++) { + Timerange tr = wqt.getTimerange(i); + Date start = new Date(tr.getStart()); + Date end = new Date(tr.getEnd()); + + wqt.get(i, wq); + + source.addData(new String[] { + df.format(start) + " - " + df.format(end), + wf.format(wq[0]), + qf.format(wq[1]), + qf.format(wq[2]), + gaugeName + }); + } + } + + + public String getReferenceGaugename() { + return FLYSUtils.getReferenceGaugeName((FLYSArtifact) master); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,256 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.HistoricalWQTimerange; +import de.intevation.flys.artifacts.model.Timerange; +import de.intevation.flys.artifacts.model.WQTimerange; +import de.intevation.flys.jfree.StyledTimeSeries; +import de.intevation.flys.utils.FLYSUtils; + +import java.util.Date; + +import org.apache.log4j.Logger; +import org.jfree.data.general.SeriesException; +import org.jfree.data.time.Day; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.w3c.dom.Document; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeCurveGenerator +extends TimeseriesChartGenerator +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(HistoricalDischargeCurveGenerator.class); + + + public static final String I18N_CHART_TITLE = + "chart.historical.discharge.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.historical.discharge.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.historical.discharge.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.historical.discharge.yaxis.label"; + + public static final String I18N_YAXIS_SECOND_LABEL = + "chart.historical.discharge.yaxis.second.label"; + + + public static enum YAXIS { + Q(0); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } + + + @Override + protected String getDefaultChartSubtitle() { + String[] args = new String[] { + FLYSUtils.getReferenceGaugeName((FLYSArtifact) master) + }; + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); + } + + @Override + protected String getDefaultYAxisLabel(int pos) { + if (pos == 0) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); + } + else if (pos == 1) { + return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL); + } + else { + return "NO TITLE FOR Y AXIS: " + pos; + } + } + + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document theme, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + logger.debug("HistoricalDischargeCurveGenerator.doOut: " + name); + logger.debug("Theme description is: " + artifactFacet.getFacetDescription()); + + + if (name.equals(HISTORICAL_DISCHARGE_Q)) { + doHistoricalDischargeOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) { + doHistoricalDischargeDifferenceOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints (artifactFacet.getData(context), + artifactFacet, + theme, visible, YAXIS.Q.idx); + } + // TODO ADD THE CASE FOR DISPLAYING W VALUES + else { + logger.warn("doOut(): unknown facet name: " + name); + return; + } + } + + + protected void doHistoricalDischargeOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible) + { + logger.debug("doHistoricalDischargeOut(): description = " + desc); + + WQTimerange wqt = (WQTimerange) data; + + TimeSeriesCollection tsc = newTimeSeriesCollection( + wqt.getTimeranges(), + wqt.getQs(), + theme, + desc); + + addAxisDataset(tsc, 0, visible); + } + + + protected void doHistoricalDischargeDifferenceOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible + ) { + logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); + + HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; + + TimeSeriesCollection tsc = newTimeSeriesCollection( + wqt.getTimeranges(), + wqt.getDiffs(), + theme, + desc); + + addAxisDataset(tsc, 0, visible); + } + + + /** + * Creates a new TimeSeriesCollection with a single TimeSeries. The + * TimeSeries will consist of two RegularTimePeriods for each W/Q value + * provided by <i>wqt</i>. This has the effect, that the line in the chart + * looks like a "step chart". + */ + protected TimeSeriesCollection newTimeSeriesCollection( + Timerange[] timeranges, + double[] values, + Document theme, + String desc + ) { + logger.debug("Create new TimeSeriesCollection for: " + desc); + + TimeSeriesCollection tsc = new TimeSeriesCollection(); + TimeSeries series = new StyledTimeSeries(desc, theme); + + for (int i = 0, n = timeranges.length; i < n; i++) { + RegularTimePeriod[] rtp = newRegularTimePeriod(timeranges[i]); + + try { + if (Double.isNaN(values[i])) { + logger.warn("Skip TimePeriod because value is NaN."); + continue; + } + + series.add(rtp[0], values[i]); + series.add(rtp[1], values[i]); + + if (logger.isDebugEnabled()) { + logger.debug("added Item to TimeSeries:"); + logger.debug(" TimePeriod: " + rtp[0] + " - " + rtp[1]); + logger.debug(" Value: " + values[i]); + } + } + catch (SeriesException se) { + logger.warn("Error while adding TimePeriod: " + se); + } + } + + tsc.addSeries(series); + + return tsc; + } + + + /** + * Creates an array that consists of two <i>Minute</i> periods [start, end]. + * + * @param timerange Supports start and end time. + * + * @return an array with two <i>Minute</i> periods [start, end]. + */ + protected RegularTimePeriod[] newRegularTimePeriod(Timerange timerange) { + Date start = new Date(timerange.getStart()); + Date end = new Date(timerange.getEnd() - 1000 * 60 * 60 * 24); + + return new RegularTimePeriod[] { + new Day(start), + new Day(end) + }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * historical discharge curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HistoricalDischargeCurveInfoGenerator +extends ChartInfoGenerator +{ + public HistoricalDischargeCurveInfoGenerator() { + super(new HistoricalDischargeCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/IdentifiableNumberAxis.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,22 @@ +package de.intevation.flys.exports; + +import org.jfree.chart.axis.NumberAxis; + + +public class IdentifiableNumberAxis extends NumberAxis { + + + protected String key; + + + protected IdentifiableNumberAxis(String key, String label) { + super(label); + this.key = key; + } + + + public String getId() { + return key; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,405 @@ +package de.intevation.flys.exports; + +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; + +import java.util.Date; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.DateAxis; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.Range; +import org.jfree.data.xy.XYDataset; + +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + +import de.intevation.flys.jfree.Bounds; + + +/** + * This class helps generating chart info documents. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class InfoGeneratorHelper { + + private static final Logger logger = + Logger.getLogger(InfoGeneratorHelper.class); + + + protected ChartGenerator generator; + + + public InfoGeneratorHelper(ChartGenerator generator) { + this.generator = generator; + } + + + /** + * Triggers the creation of the chart info document. + * + * @param chart The JFreeChart chart. + * @param info An info object that has been created while chart creation. + * + * @return the info document. + */ + public Document createInfoDocument( + JFreeChart chart, + ChartRenderingInfo info) + { + logger.debug("InfoGeneratorHelper.createInfoDocument"); + + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element chartinfo = cr.create("chartinfo"); + + chartinfo.appendChild(createAxesElements(cr, chart)); + chartinfo.appendChild(createTransformationElements(cr, chart, info)); + + doc.appendChild(chartinfo); + + return doc; + } + + + /** + * This method create a axes element that contains all domain and range + * axes of the given chart. + * + * @param cr The ElementCreator. + * @param chart The chart that provides range information of its axes. + * + * @return an element with axes information. + */ + protected Element createAxesElements( + ElementCreator cr, + JFreeChart chart) + { + logger.debug("InfoGeneratorHelper.createRangeElements"); + + Element axes = cr.create("axes"); + + XYPlot plot = (XYPlot) chart.getPlot(); + + int dAxisCount = plot.getDomainAxisCount(); + for (int i = 0; i < dAxisCount; i++) { + ValueAxis axis = plot.getDomainAxis(i); + XYDataset data = plot.getDataset(i); + + if (axis != null) { + Element e = createAxisElement(cr, axis, data, "domain", i); + axes.appendChild(e); + } + } + + int rAxisCount = plot.getRangeAxisCount(); + for (int i = 0; i < rAxisCount; i++) { + ValueAxis axis = plot.getRangeAxis(i); + XYDataset data = plot.getDataset(i); + + if (axis == null || data == null) { + logger.warn("Axis or dataset is empty at pos: " + i); + continue; + } + + Element e = createAxisElement(cr, axis, data, "range", i); + axes.appendChild(e); + } + + return axes; + } + + + /** + * This method create a axis element for a given <i>axis</i> and + * <i>type</i>. Type can be one of 'domain' or 'range'. + * + * @param cr The ElementCreator + * @param axis The axis that provides range information. + * @param dataset The dataset for min/max determination. + * @param type The axis type ('domain' or 'range'). + * @param pos The position in the chart. + * + * @return An element that contains range information of a given axis. + */ + protected Element createAxisElement( + ElementCreator cr, + ValueAxis axis, + XYDataset dataset, + String type, + int pos) + { + logger.debug("createAxisElement " + pos); + logger.debug("Axis is from type: " + axis.getClass()); + + Element e = cr.create(type); + cr.addAttr(e, "pos", String.valueOf(pos), true); + + if (axis instanceof DateAxis) { + prepareDateAxisElement( + e, cr, (DateAxis) axis, dataset, type, pos); + } + else { + prepareNumberAxisElement( + e, cr, (NumberAxis) axis, dataset, type, pos); + } + + return e; + } + + + protected Element prepareNumberAxisElement( + Element e, + ElementCreator cr, + NumberAxis axis, + XYDataset dataset, + String type, + int pos + ) { + Range range = axis.getRange(); + + cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true); + cr.addAttr(e, "to", String.valueOf(range.getUpperBound()), true); + cr.addAttr(e, "axistype", "number", true); + + Range[] rs = generator.getRangesForAxis(pos); + Range r = null; + + if (type.equals("range")) { + r = rs[1]; + } + else { + r = rs[0]; + } + + cr.addAttr(e, "min", String.valueOf(r.getLowerBound()), true); + cr.addAttr(e, "max", String.valueOf(r.getUpperBound()), true); + + return e; + } + + + protected Element prepareDateAxisElement( + Element e, + ElementCreator cr, + DateAxis axis, + XYDataset dataset, + String type, + int pos + ) { + Date from = axis.getMinimumDate(); + Date to = axis.getMaximumDate(); + + Bounds bounds = null; + if (type.equals("range")) { + bounds = generator.getYBounds(pos); + } + else { + bounds = generator.getXBounds(pos); + } + + cr.addAttr(e, "axistype", "date", true); + cr.addAttr(e, "from", String.valueOf(from.getTime()), true); + cr.addAttr(e, "to", String.valueOf(to.getTime()), true); + + cr.addAttr(e, "min", bounds.getLower().toString(), true); + cr.addAttr(e, "max", bounds.getUpper().toString(), true); + + return e; + } + + + /** + * This method appends the values of a transformation matrix to transform + * image pixel coordinates into chart coordinates. + * + * @param cr The ElementCreator. + * @param chart The chart object. + * @param info The ChartRenderingInfo that is filled while chart creation. + * + * @return an element that contains one or more transformation matrix. + */ + protected Element createTransformationElements( + ElementCreator cr, + JFreeChart chart, + ChartRenderingInfo info) + { + logger.debug("InfoGeneratorHelper.createTransformationElements"); + + Element tf = cr.create("transformation-matrix"); + + Rectangle2D dataArea = info.getPlotInfo().getDataArea(); + + XYPlot plot = (XYPlot) chart.getPlot(); + ValueAxis xAxis = plot.getDomainAxis(); + + if (xAxis == null) { + logger.error("There is no x axis in the chart!"); + return null; + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis yAxis = plot.getRangeAxis(i); + + if (yAxis == null) { + logger.warn("No y axis at pos " + i + " existing."); + continue; + } + + Element matrix = createTransformationElement( + cr, xAxis, yAxis, dataArea, i); + + tf.appendChild(matrix); + } + + return tf; + } + + + /** + * Creates an element that contains values used to transform coordinates + * of a coordinate system A into a coordinate system B. + * + * @param cr The ElementCreator. + * @param xAxis The x axis of the target coordinate system. + * @param yAxis The y axis of the target coordinate system. + * @param dataArea The pixel coordinates of the chart image. + * @param pos The dataset position. + * + * @return an element that contains transformation matrix values. + */ + protected Element createTransformationElement( + ElementCreator cr, + ValueAxis xAxis, + ValueAxis yAxis, + Rectangle2D dataArea, + int pos) + { + double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis); + + Element matrix = cr.create("matrix"); + + cr.addAttr(matrix, "pos", String.valueOf(pos), true); + cr.addAttr(matrix, "sx", String.valueOf(tm[0]), true); + cr.addAttr(matrix, "sy", String.valueOf(tm[1]), true); + cr.addAttr(matrix, "tx", String.valueOf(tm[2]), true); + cr.addAttr(matrix, "ty", String.valueOf(tm[3]), true); + + if (xAxis instanceof DateAxis) { + cr.addAttr(matrix, "xtype", "date", true); + } + else { + cr.addAttr(matrix, "xtype", "number", true); + } + + if (yAxis instanceof DateAxis) { + cr.addAttr(matrix, "ytype", "date", true); + } + else { + cr.addAttr(matrix, "ytype", "number", true); + } + + return matrix; + } + + + /** + * This method determines a transformation matrix to transform pixel + * coordinates of the chart image into chart coordinates. + * + * @param dataArea The rectangle that contains the data points of the chart. + * @param xAxis The x axis. + * @param yAxis The y axis. + * + * @return a double array as follows: [sx, sy, tx, ty]. + */ + protected static double[] createTransformationMatrix( + Rectangle2D dataArea, + ValueAxis xAxis, + ValueAxis yAxis) + { + logger.debug("InfoGeneratorHelper.createTransformationMatrix"); + + double offsetX = dataArea.getX(); + double width = dataArea.getWidth(); + double offsetY = dataArea.getY(); + double height = dataArea.getHeight(); + + Range xRange = getRangeFromAxis(xAxis); + Range yRange = getRangeFromAxis(yAxis); + + double lowerX = xRange.getLowerBound(); + double upperX = xRange.getUpperBound(); + double lowerY = yRange.getLowerBound(); + double upperY = yRange.getUpperBound(); + + if (xAxis.isInverted()) { + logger.info("X-Axis is inverted!"); + + double tmp = upperX; + upperX = lowerX; + lowerX = tmp; + } + + double dMoveX = upperX - lowerX; + double fMoveX = width * lowerX; + double dMoveY = lowerY - upperY; + double fMoveY = height * upperY; + + AffineTransform t1 = AffineTransform.getTranslateInstance( + offsetX - ( fMoveX / dMoveX ), + offsetY - ( fMoveY / dMoveY ) ); + + AffineTransform t2 = AffineTransform.getScaleInstance( + width / (upperX - lowerX), + height / (lowerY - upperY)); + + t1.concatenate(t2); + + try { + t1.invert(); + + double[] c = new double[6]; + t1.getMatrix(c); + + return new double[] { c[0], c[3], c[4], c[5] }; + } + catch (NoninvertibleTransformException e) { + // do nothing + logger.warn("Matrix is not invertible."); + } + + return new double[] { 1d, 1d, 0d, 0d }; + } + + + protected static Range getRangeFromAxis(ValueAxis axis) { + if (axis instanceof DateAxis) { + DateAxis dAxis = (DateAxis) axis; + Date min = dAxis.getMinimumDate(); + Date max = dAxis.getMaximumDate(); + + return new Range(min.getTime(), max.getTime()); + } + else { + return axis.getRange(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/IntegerAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,37 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class IntegerAttribute extends VisibleAttribute { + + + public IntegerAttribute(String name, int value, boolean visible) { + super(name, value, visible); + } + + + /** + * Calls VisibleAttribute.toXML() and appends afterwards an attribute + * <i>type</i> with value <i>integer</i>. + * + * @param parent The parent Node. + * + * @return the new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("type", "integer"); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LegendProcessor.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,148 @@ +package de.intevation.flys.exports; + +import java.awt.geom.Line2D; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.plot.XYPlot; + + +/** Class to process Plots legends. */ +public abstract class LegendProcessor { + + /** (Empty) shape for aggregated Legend Items. */ + private static final Line2D.Double SPACE = new Line2D.Double(0,0,0,0); + + + /** Prevent instantiations. */ + private LegendProcessor() { + } + + + /** + * Create a hash from a legenditem. + * This hash can then be used to merge legend items labels. + * @return hash for given legenditem to identify mergeables. + */ + protected static String legendItemHash(LegendItem li) { + // TODO Do proper implementation. Ensure that only mergable sets are created. + // getFillPaint() + // getFillPaintTransformer() + // getLabel() + // getLine() + // getLinePaint() + // getLineStroke() + // getOutminePaint() + // getOutlineStroke() + // Shape getShape() + // String getToolTipText() + // String getURLText() + // boolean isLineVisible() + // boolean isShapeFilled() + // boolean isShapeOutlineVisible() + // boolean isShapeVisible() + String hash = li.getLinePaint().toString(); + String label = li.getLabel(); + /*if (label.startsWith("W (") || label.startsWith("W(")) { + hash += "-W-"; + } + else if (label.startsWith("Q(") || label.startsWith("Q (")) { + hash += "-Q-"; + }*/ + + // WQ.java holds example of using regex Matcher/Pattern. + + return hash; + } + + + /** + * Create new legend entries, dependent on settings. + * @param plot The plot for which to modify the legend. + * @param threshold How many items are needed for aggregation to + * be triggered? + */ + public static void aggregateLegendEntries(XYPlot plot, int threshold) { + LegendItemCollection old = plot.getLegendItems(); + // Find "similar" entries if aggregation is enabled. + + int maxListSize = 0; + int AGGR_THRESHOLD = threshold; + + if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0){ + return; + } + + HashMap<String, List<LegendItem>> entries = new LinkedHashMap<String, List<LegendItem>>(); + for (Iterator i = old.iterator(); i.hasNext();) { + LegendItem item = (LegendItem) i.next(); + String hash = legendItemHash(item); + List<LegendItem> itemList = entries.get(hash); + if (itemList == null) { + itemList = new ArrayList<LegendItem>(); + } + itemList.add(item); + + if (itemList.size() > maxListSize) { + maxListSize = itemList.size(); + } + + entries.put(legendItemHash(item), itemList); + } + + if (maxListSize < AGGR_THRESHOLD) { + // No need to do anything. + return; + } + + // Run over collected entries, merge their names and create new + // entry if needed. + LegendItemCollection newLegend = new LegendItemCollection(); + for (Map.Entry<String, List<LegendItem>> cursor: entries.entrySet()) { + List<LegendItem> itemList = cursor.getValue(); + if (itemList.size() >= AGGR_THRESHOLD) { + // Now do merging. + LegendItem item = (LegendItem) itemList.get(0); + // Unfortunately we cannot clone and just setDescription, as this + // method was added in JFreeChart 1.0.14 (we are at .13). + + // Remove the shapes of all but the first items, + // to prevent "overfill" of legenditemblock. + for (int i = 0; i < itemList.size(); i++) { + if (i != 0) { + LegendItem litem = itemList.get(i); + + // Make shape and line really small. + LegendItem merged = new LegendItem( + "," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(), + litem.getURLText(), false, SPACE, + false, litem.getFillPaint(), false, + litem.getOutlinePaint(), litem.getOutlineStroke(), false, + SPACE, litem.getLineStroke(), litem.getLinePaint()); + newLegend.add(merged); + } + else { + newLegend.add(itemList.get(i)); + } + } + } + else { + // Do not merge entries. + for (LegendItem li: itemList) { + newLegend.add(li); + } + } + } + + plot.setFixedLegendItems (newLegend); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LegendSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,54 @@ +package de.intevation.flys.exports; + + +/** + * Settings regarding legend of chart. + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class LegendSection extends TypeSection { + + public static final String VISIBILITY_ATTR = "visibility"; + public static final String FONTSIZE_ATTR = "font-size"; + public static final String AGGREGATION_ATTR = "aggregation-threshold"; + + + public LegendSection() { + super("legend"); + } + + + /** Register font size attribute and value. */ + public void setFontSize(int fontSize) { + if (fontSize <= 0) { + return; + } + + setIntegerValue(FONTSIZE_ATTR, fontSize); + } + + + public Integer getFontSize() { + return getIntegerValue(FONTSIZE_ATTR); + } + + + public Integer getAggregationThreshold() { + return getIntegerValue(AGGREGATION_ATTR); + } + + + public void setAggregationThreshold(int aggregationThreshold) { + setIntegerValue(AGGREGATION_ATTR, Math.abs(aggregationThreshold)); + } + + + public void setVisibility(boolean visibility) { + setBooleanValue(VISIBILITY_ATTR, visibility); + } + + + public Boolean getVisibility() { + return getBooleanValue(VISIBILITY_ATTR); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,686 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.geom.Lines; +import de.intevation.flys.artifacts.model.AreaFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledAreaSeriesCollection; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.utils.DataUtil; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.ThemeUtil; + +import org.apache.log4j.Logger; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + + +/** + * An OutGenerator that generates longitudinal section curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class LongitudinalSectionGenerator +extends XYChartGenerator +implements FacetTypes +{ + public enum YAXIS { + W(0), + D(1), + Q(2); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** The logger that is used in this generator. */ + private static Logger logger = + Logger.getLogger(LongitudinalSectionGenerator.class); + + /** Key to look up internationalized String for annotations label. */ + public static final String I18N_ANNOTATIONS_LABEL = + "chart.longitudinal.annotations.label"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * titles. + */ + public static final String I18N_CHART_TITLE = + "chart.longitudinal.section.title"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * subtitles. + */ + public static final String I18N_CHART_SUBTITLE = + "chart.longitudinal.section.subtitle"; + + /** + * Key to look up internationalized String for LongitudinalSection diagrams + * short subtitles. + */ + public static final String I18N_CHART_SHORT_SUBTITLE = + "chart.longitudinal.section.shortsubtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.longitudinal.section.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.longitudinal.section.yaxis.label"; + + public static final String I18N_2YAXIS_LABEL = + "chart.longitudinal.section.yaxis.second.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "W-L\u00e4ngsschnitt"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "km"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]"; + public static final String I18N_2YAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]"; + + public final static String I18N_WDIFF_YAXIS_LABEL = + "chart.w_differences.yaxis.label"; + + public final static String I18N_WDIFF_YAXIS_LABEL_DEFAULT = "m"; + + /** Whether or not the plot is inverted (left-right). */ + protected boolean inverted; + + + public LongitudinalSectionGenerator() { + super(); + } + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + /** True if x axis has been inverted. */ + public boolean isInverted() { + return inverted; + } + + + /** Set to true if x axis has been inverted. */ + public void setInverted(boolean inverted) { + this.inverted = inverted; + } + + /** + * Return left most data points x value (on first axis). + * Overridden because axis could be inverted. + */ + @Override + protected double getLeftX() { + if (isInverted()) { + return (Double)getXBounds(0).getUpper(); + } + return (Double)getXBounds(0).getLower(); + } + + + /** + * Return right most data points x value (on first axis). + * Overridden because axis could be inverted. + */ + @Override + protected double getRightX() { + if (isInverted()) { + return (Double)getXBounds(0).getLower(); + } + return (Double)getXBounds(0).getUpper(); + } + + + /** + * Returns the default title for this chart. + * + * @return the default title for this chart. + */ + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + + /** + * Returns the default subtitle for this chart. + * + * @return the default subtitle for this chart. + */ + @Override + protected String getDefaultChartSubtitle() { + double[] dist = getRange(); + + Object[] args = null; + if (dist == null) { + args = new Object[] {getRiverName()}; + return msg(getChartShortSubtitleKey(), "", args); + } + args = new Object[] { + getRiverName(), + dist[0], + dist[1] + }; + return msg(getChartSubtitleKey(), "", args); + } + + + /** + * Gets key to look up internationalized String for the charts subtitle. + * @return key to look up translated subtitle. + */ + protected String getChartSubtitleKey() { + return I18N_CHART_SUBTITLE; + } + + + /** + * Gets key to look up internationalized String for the charts short + * subtitle. + * @return key to look up translated subtitle. + */ + protected String getChartShortSubtitleKey() { + return I18N_CHART_SHORT_SUBTITLE; + } + + + /** + * Get internationalized label for the x axis. + */ + @Override + protected String getDefaultXAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg( + I18N_XAXIS_LABEL, + I18N_XAXIS_LABEL_DEFAULT, + new Object[] { FLYSUtils.getRiver(flys).getName() }); + } + + + @Override + protected String getDefaultYAxisLabel(int index) { + String label = "default"; + + if (index == YAXIS.W.idx) { + label = getWAxisLabel(); + } + else if (index == YAXIS.Q.idx) { + label = msg(getQAxisLabelKey(), getQAxisDefaultLabel()); + } + else if (index == YAXIS.D.idx) { + label = msg(I18N_WDIFF_YAXIS_LABEL, I18N_WDIFF_YAXIS_LABEL_DEFAULT); + } + + return label; + } + + + /** + * Get internationalized label for the y axis. + */ + protected String getWAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + String unit = FLYSUtils.getRiver(flys).getWstUnit().getName(); + + return msg( + I18N_YAXIS_LABEL, + I18N_YAXIS_LABEL_DEFAULT, + new Object[] { unit }); + } + + + /** + * Create Axis for given index. + * @return axis with according internationalized label. + */ + @Override + protected NumberAxis createYAxis(int index) { + NumberAxis axis = super.createYAxis(index); + + // "Q" Axis shall include 0. + if (index == YAXIS.Q.idx) { + axis.setAutoRangeIncludesZero(true); + } + else { + axis.setAutoRangeIncludesZero(false); + } + + return axis; + } + + + /** + * Get default value for the second Y-Axis' label (if no translation was + * found). + */ + protected String getQAxisDefaultLabel() { + return I18N_2YAXIS_LABEL_DEFAULT; + } + + + /** + * Get key for internationalization of the second Y-Axis' label. + */ + protected String getQAxisLabelKey() { + return I18N_2YAXIS_LABEL; + } + + + /** + * Trigger inversion. + */ + @Override + protected void adjustAxes(XYPlot plot) { + super.adjustAxes(plot); + invertXAxis(plot.getDomainAxis()); + } + + + /** + * This method inverts the x-axis based on the kilometer information of the + * selected river. If the head of the river is at kilometer 0, the axis is + * not inverted, otherwise it is. + * + * @param xaxis The domain axis. + */ + protected void invertXAxis(ValueAxis xaxis) { + if (inverted) { + logger.debug("X-Axis.setInverted(true)"); + xaxis.setInverted(true); + } + } + + + /** + * Produce output. + * @param artifactAndFacet current facet and artifact. + * @param attr theme for facet + */ + @Override + public void doOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + String name = artifactAndFacet.getFacetName(); + + logger.debug("LongitudinalSectionGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + Facet facet = artifactAndFacet.getFacet(); + + if (facet == null) { + return; + } + + if (name.equals(LONGITUDINAL_W)) { + doWOut( + (WQKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(LONGITUDINAL_Q)) { + doQOut( + (WQKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(LONGITUDINAL_ANNOTATION)) { + doAnnotations( + (FLYSAnnotation) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(STATIC_WKMS) + || name.equals(HEIGHTMARKS_POINTS) + || name.equals(STATIC_WQKMS)) { + doWOut( + (WKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(STATIC_WQKMS_W)) { + doWOut( + (WQKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(STATIC_WQKMS_Q)) { + doQOut( + (WQKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(W_DIFFERENCES)) { + doWDifferencesOut( + (WKms) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.AREA(name)) { + doArea( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible, + YAXIS.W.idx); + } + else { + logger.warn("Unknown facet name: " + name); + return; + } + } + + + /** + * Process the output for W facets in a longitudinal section curve. + * + * @param wkms WKms data. + * @param aandf The artifact and facet. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + */ + protected void doWOut( + WKms wkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("LongitudinalSectionGenerator.doWOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, wkms); + addAxisSeries(series, YAXIS.W.idx, visible); + + // If a "band around the curve shall be drawn, add according area. + double bandWidth = ThemeUtil.parseBandWidth(theme); + if (bandWidth > 0 ) { + XYSeries seriesDown = new StyledXYSeries( + "band " + aandf.getFacetDescription(), false, theme); + XYSeries seriesUp = new StyledXYSeries( + aandf.getFacetDescription()+"+/-"+bandWidth, false, theme); + StyledSeriesBuilder.addUpperBand(seriesUp, wkms, bandWidth); + StyledSeriesBuilder.addLowerBand(seriesDown, wkms, bandWidth); + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); + area.addSeries(seriesUp); + area.addSeries(seriesDown); + area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); + addAreaSeries(area, YAXIS.W.idx, visible); + } + + if (needInvertAxis(wkms)) { + setInverted(true); + } + } + + + /** + * Add items to dataseries which describes the differences. + */ + protected void doWDifferencesOut( + WKms wkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("WDifferencesCurveGenerator.doWDifferencesOut"); + if (wkms == null) { + logger.warn("No data to add to WDifferencesChart."); + return; + } + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + if (logger.isDebugEnabled()) { + if (wkms.size() > 0) { + logger.debug("Generate series: " + series.getKey()); + logger.debug("Start km: " + wkms.getKm(0)); + logger.debug("End km: " + wkms.getKm(wkms.size() - 1)); + logger.debug("Values : " + wkms.size()); + } + } + + StyledSeriesBuilder.addPoints(series, wkms); + + addAxisSeries(series, YAXIS.D.idx, visible); + if (DataUtil.guessWaterIncreasing(wkms.allWs())) { + setInverted(true); + } + } + + + /** + * Process the output for Q facets in a longitudinal section curve. + * + * @param wqkms An array of WQKms values. + * @param aandf The facet and artifact. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + */ + protected void doQOut( + WQKms wqkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("LongitudinalSectionGenerator.doQOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); + + addAxisSeries(series, YAXIS.Q.idx, visible); + + if (needInvertAxis(wqkms)) { + setInverted(true); + } + } + + /** + * This method determines - taking JFreeCharts auto x value ordering into + * account - if the x axis need to be inverted. Waterlines in these charts + * should decrease. + * + * @param wkms The data object that stores the x and y values used for this + * chart. + */ + public boolean needInvertAxis(WKms wkms) { + boolean wsUp = wkms.guessWaterIncreasing(); + boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms()); + boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp); + + int size = wkms.size(); + + if (logger.isDebugEnabled()) { + logger.debug("(Wkms)Values : " + size); + if (size > 0) { + logger.debug("Start km: " + wkms.getKm(0)); + logger.debug("End km: " + wkms.getKm(size-1)); + } + logger.debug("wsUp: " + wsUp); + logger.debug("kmUp: " + kmUp); + logger.debug("inv: " + inv); + } + + return inv; + } + + + /** + * Get name of series (displayed in legend). + * @return name of the series. + */ + protected String getSeriesName(WQKms wqkms, String mode) { + String name = wqkms.getName(); + String prefix = name != null && name.indexOf(mode) >= 0 ? null : mode; + + return prefix != null && prefix.length() > 0 + ? prefix + "(" + name +")" + : name; + } + + + /** Look up the axis identifier for a given facet type. */ + public int axisIdxForFacet(String facetName) { + if (FacetTypes.IS.W(facetName)) { + return YAXIS.W.idx; + } + else if (FacetTypes.IS.Q(facetName)) { + return YAXIS.Q.idx; + } + else { + logger.warn("Could not find axis for facet " + facetName); + return YAXIS.W.idx; + } + } + + + /** + * Do Area out. + * @param theme styling information. + * @param visible whether or not visible. + */ + protected void doArea( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("LongitudinalSectionGenerator.doArea"); + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); + + String seriesName = aandf.getFacetDescription(); + + AreaFacet.Data data = (AreaFacet.Data) o; + + XYSeries up = null; + XYSeries down = null; + + if (data.getUpperData() != null) { + up = new StyledXYSeries(seriesName, false, theme); + if (data.getUpperData() instanceof WQKms) { + if (FacetTypes.IS.Q(data.getRootFacetName())) { + StyledSeriesBuilder.addPointsKmQ(up, (WQKms) data.getUpperData()); + } + else { + StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData()); + } + } + else if (data.getUpperData() instanceof double[][]) { + StyledSeriesBuilder.addPoints(up, (double [][]) data.getUpperData(), false); + } + else if (data.getUpperData() instanceof WKms) { + StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData()); + } + else if (data.getUpperData() instanceof Lines.LineData) { + StyledSeriesBuilder.addPoints(up, ((Lines.LineData) data.getUpperData()).points, false); + } + else { + logger.error("Do not know how to deal with (up) area info from: " + + data.getUpperData()); + } + } + + // TODO Depending on style, the area (e.g. 20m^2) should be added as annotation. + + if (data.getLowerData() != null) { + // TODO: Sort this out: when the two series have the same name, + // the renderer (or anything in between) will not work correctly. + down = new StyledXYSeries(seriesName + " ", false, theme); + if (data.getLowerData() instanceof WQKms) { + if (FacetTypes.IS.Q(data.getRootFacetName())) { + StyledSeriesBuilder.addPointsKmQ(down, (WQKms) data.getLowerData()); + } + else { + StyledSeriesBuilder.addPoints(down, (WQKms) data.getLowerData()); + } + } + else if (data.getLowerData() instanceof double[][]) { + StyledSeriesBuilder.addPoints(down, (double[][]) data.getLowerData(), false); + } + else if (data.getLowerData() instanceof WKms) { + StyledSeriesBuilder.addPoints(down, (WKms) data.getLowerData()); + } + else if (data.getLowerData() instanceof Lines.LineData) { + StyledSeriesBuilder.addPoints(down, ((Lines.LineData) data.getLowerData()).points, false); + } + else { + logger.error("Do not know how to deal with (down) area info from: " + + data.getLowerData()); + } + } + + if (up == null && down != null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE); + down.setKey(seriesName); + area.addSeries(down); + area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(down)); + } + else if (up != null && down == null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER); + area.addSeries(up); + area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(up)); + } + else if (up != null && down != null) { + if (data.doPaintBetween()) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); + } + else { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE); + } + area.addSeries(up); + area.addSeries(down); + } + // Add area to the respective axis. + addAreaSeries(area, axisIdxForFacet(data.getRootFacetName()), visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * longitudinal section curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class LongitudinalSectionInfoGenerator +extends ChartInfoGenerator +{ + public LongitudinalSectionInfoGenerator() { + super(new LongitudinalSectionGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MapGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,327 @@ +package de.intevation.flys.exports; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet; +import de.intevation.flys.artifacts.model.map.WMSLayerFacet; +import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet; +import de.intevation.flys.collections.FLYSArtifactCollection; +import de.intevation.flys.utils.GeometryUtils; +import de.intevation.flys.utils.MapfileGenerator; +import de.intevation.flys.utils.ThemeUtil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +public class MapGenerator implements OutGenerator, FacetTypes { + + private static Logger logger = Logger.getLogger(MapGenerator.class); + + protected FLYSArtifactCollection collection; + + protected Artifact master; + + protected Settings settings; + + protected Document request; + + protected OutputStream out; + + protected CallContext context; + + protected List<WMSLayerFacet> layers; + + protected Envelope maxExtent; + protected Envelope initialExtent; + + protected String srid; + + + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("MapGenerator.init"); + + this.request = request; + this.out = out; + this.context = context; + + this.layers = new ArrayList<WMSLayerFacet>(); + + this.maxExtent = null; + this.initialExtent = null; + } + + + @Override + public void setMasterArtifact(Artifact master) { + logger.debug("MapGenerator.setMasterArtifact"); + this.master = master; + } + + @Override + public void setCollection(FLYSArtifactCollection collection) { + this.collection = collection; + } + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible) + { + String name = artifactFacet.getFacetName(); + + logger.debug("MapGenerator.doOut: " + + artifactFacet.getArtifact().identifier() + " | " + name); + FLYSArtifact flys = (FLYSArtifact) artifactFacet.getArtifact(); + + Facet nativeFacet = artifactFacet.getFacet(); + + if (nativeFacet instanceof WMSLayerFacet) { + WMSLayerFacet wms = (WMSLayerFacet) nativeFacet; + Envelope extent = wms.getExtent(); + + layers.add(wms); + + setMaxExtent(extent); + setSrid(wms.getSrid()); + + if (FLOODMAP_WSPLGEN.equals(name)) { + setInitialExtent(extent); + createWSPLGENLayer(flys, wms, attr); + } + else if (FLOODMAP_BARRIERS.equals(name)) { + createBarriersLayer(flys, wms); + } + else if (FLOODMAP_USERSHAPE.equals(name)) { + createUserShapeLayer(flys, wms); + } + else { + createDatabaseLayer(flys, wms, attr); + } + } + else { + logger.warn("Facet not supported: " + nativeFacet.getClass()); + } + } + + + protected void createWSPLGENLayer( + FLYSArtifact flys, + WMSLayerFacet wms, + Document attr + ) { + try { + if(wms instanceof WSPLGENLayerFacet) { + MapfileGenerator mfg = MapfileGenerator.getInstance(); + mfg.createUeskLayer( + flys, + (WSPLGENLayerFacet) wms, + ThemeUtil.createWSPLGENStyle(attr), + context); + } + else { + logger.warn("Cannot create WSPLGEN layer from: " + + wms.getClass()); + } + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + } + + + protected void createBarriersLayer(FLYSArtifact flys, WMSLayerFacet wms) { + MapfileGenerator mfg = MapfileGenerator.getInstance(); + + try { + mfg.createBarriersLayer(flys, wms); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + } + + + protected void createUserShapeLayer(FLYSArtifact flys, WMSLayerFacet wms) { + MapfileGenerator mfg = MapfileGenerator.getInstance(); + + try { + mfg.createUserShapeLayer(flys, wms); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + } + + + protected void createDatabaseLayer( + FLYSArtifact flys, + WMSLayerFacet wms, + Document attr + ) { + logger.debug("createDatabaseLayer for facet: " + wms.getName()); + + MapfileGenerator mfg = MapfileGenerator.getInstance(); + + try { + File baseDir = mfg.getShapefileBaseDir(); + File artDir = new File(baseDir, flys.identifier()); + + if (artDir != null && !artDir.exists()) { + logger.debug("Create new directory: " + artDir.getPath()); + artDir.mkdir(); + } + + if (wms instanceof WMSDBLayerFacet) { + mfg.createDatabaseLayer( + flys, + (WMSDBLayerFacet) wms, + ThemeUtil.createMapserverStyle(attr)); + } + else { + logger.warn("Cannot create DB layer from: " + wms.getClass()); + } + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + } + + + @Override + public void generate() + throws IOException + { + logger.debug("MapGenerator.generate"); + + MapfileGenerator.getInstance().update(); + + Document response = XMLUtils.newDocument(); + ElementCreator c = new ElementCreator( + response, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element root = c.create("floodmap"); + Element layers = c.create("layers"); + + response.appendChild(root); + root.appendChild(layers); + + appendLayers(layers); + appendMapInformation(root, c); + + XMLUtils.toStream(response, out); + } + + + protected void appendLayers(Element parent) { + for (WMSLayerFacet facet: layers) { + parent.appendChild(facet.toXML(parent.getOwnerDocument())); + } + } + + + protected void setMaxExtent(Envelope maxExtent) { + if (maxExtent == null) { + return; + } + + if (this.maxExtent == null) { + logger.debug("Set max extent to: " + maxExtent); + this.maxExtent = new Envelope(maxExtent); + return; + } + + this.maxExtent.expandToInclude(maxExtent); + } + + + protected void setInitialExtent(Envelope initialExtent) { + if (this.initialExtent == null && initialExtent != null) { + logger.debug("Set initial extent to: " + initialExtent); + this.initialExtent = new Envelope(initialExtent); + } + } + + + protected void setSrid(String srid) { + if (srid == null || srid.length() == 0) { + return; + } + + this.srid = srid; + } + + + protected void appendMapInformation(Element parent, ElementCreator c) { + String mE = GeometryUtils.jtsBoundsToOLBounds(this.maxExtent); + + Element maxExtent = c.create("maxExtent"); + maxExtent.setTextContent(mE); + + if(this.initialExtent != null) { + String iE = GeometryUtils.jtsBoundsToOLBounds(this.initialExtent); + Element initExtent = c.create("initialExtent"); + initExtent.setTextContent(iE); + parent.appendChild(initExtent); + } + + Element srid = c.create("srid"); + srid.setTextContent(this.srid); + + // TODO zoom levels + // TODO resolutation + + parent.appendChild(maxExtent); + parent.appendChild(srid); + } + + + /** + * Returns an instance of <i>EmptySettings</i> currently! + * + * @return an instance of <i>EmptySettings</i>. + */ + @Override + public Settings getSettings() { + return new EmptySettings(); + } + + + @Override + public void setSettings(Settings settings) { + this.settings = settings; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,158 @@ +package de.intevation.flys.exports; + +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.MiddleBedHeightData; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MiddleBedHeightExporter extends AbstractExporter { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(MiddleBedHeightExporter.class); + + public static final String CSV_KM = + "export.bedheight_middle.csv.header.km"; + + public static final String CSV_SOUNDING = + "export.bedheight_middle.csv.header.sounding"; + + public static final String CSV_HEIGHT = + "export.bedheight_middle.csv.header.height"; + + public static final String CSV_UNCERTAINTY = + "export.bedheight_middle.csv.header.uncertainty"; + + public static final String CSV_DATA_GAP = + "export.bedheight_middle.csv.header.datagap"; + + public static final String CSV_SOUNDING_WIDTH = + "export.bedheight_middle.csv.header.soundingwidth"; + + public static final String CSV_WIDTH = + "export.bedheight_middle.csv.header.width"; + + public static final String CSV_LOCATIONS = + "export.bedheight_middle.csv.header.locations"; + + + protected List<MiddleBedHeightData[]> data; + + + public void init(Document request, OutputStream out, CallContext cc) { + super.init(request, out, cc); + data = new ArrayList<MiddleBedHeightData[]>(); + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult) d).getData(); + + if (d instanceof MiddleBedHeightData[]) { + logger.debug("Add new data of type MiddleBedHeightData"); + data.add((MiddleBedHeightData[]) d); + } + } + } + + + @Override + protected void writeCSVData(CSVWriter writer) { + logger.info("MiddleBedHeightExporter.writeCSVData"); + logger.debug("CSV gets " + data.size() + " MiddleBedHeightData objects."); + + writeCSVHeader(writer); + + for (MiddleBedHeightData[] d: data) { + data2CSV(writer, d); + } + } + + + protected void writeCSVHeader(CSVWriter writer) { + writer.writeNext(new String[] { + msg(CSV_KM, CSV_KM), + msg(CSV_SOUNDING, CSV_SOUNDING), + msg(CSV_HEIGHT, CSV_HEIGHT), + msg(CSV_UNCERTAINTY, CSV_UNCERTAINTY), + msg(CSV_DATA_GAP, CSV_DATA_GAP), + msg(CSV_SOUNDING_WIDTH, CSV_SOUNDING_WIDTH), + msg(CSV_WIDTH, CSV_WIDTH), + msg(CSV_LOCATIONS, CSV_LOCATIONS) + }); + } + + + protected void data2CSV(CSVWriter writer, MiddleBedHeightData[] mData) { + logger.debug("Add next MiddleBedHeightData to CSV"); + + FLYSArtifact flys = (FLYSArtifact) master; + + NumberFormat kmF = Formatter.getMiddleBedHeightKM(context); + NumberFormat heightF = Formatter.getMiddleBedHeightHeight(context); + NumberFormat uncertF = Formatter.getMiddleBedHeightUncert(context); + NumberFormat gapF = Formatter.getMiddleBedHeightDataGap(context); + NumberFormat soundF = Formatter.getMiddleBedHeightSounding(context); + NumberFormat widthF = Formatter.getMiddleBedHeightWidth(context); + + for (MiddleBedHeightData data: mData) { + for (int i = 0, n = data.size(); i < n; i++) { + int start = data.getStartYear(); + int end = data.getEndYear(); + + if (start == end) { + writer.writeNext(new String[] { + kmF.format(data.getKM(i)), + data.getSoundingName(context), + heightF.format(data.getMiddleHeight(i)), + uncertF.format(data.getUncertainty(i)), + gapF.format(data.getDataGap(i)) + "%", + soundF.format(data.getSoundingWidth(i)), + widthF.format(data.getWidth(i)), + FLYSUtils.getLocationDescription(flys, data.getKM(i)), + }); + } + else { + writer.writeNext(new String[] { + kmF.format(data.getKM(i)), + data.getSoundingName(context), + heightF.format(data.getMiddleHeight(i)), + "", + "", + "", + "", + FLYSUtils.getLocationDescription(flys, data.getKM(i)), + }); + } + + } + } + } + + + @Override + protected void writePDF(OutputStream out) { + logger.error("TODO: Implement FlowVelocityExporter.writePDF"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,248 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +import org.jfree.data.xy.XYSeries; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.MiddleBedHeightData; + +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; + +import de.intevation.flys.utils.FLYSUtils; + + +/** + * An OutGenerator that generates middle bed height charts. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MiddleBedHeightGenerator +extends XYChartGenerator +implements FacetTypes +{ + public enum YAXIS { + H(0); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(MiddleBedHeightGenerator.class); + + /** Key to look up internationalized String for annotations label. */ + public static final String I18N_ANNOTATIONS_LABEL = + "chart.bedheight_middle.annotations.label"; + + public static final String I18N_CHART_TITLE = + "chart.bedheight_middle.section.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.bedheight_middle.section.subtitle"; + + public static final String I18N_CHART_SHORT_SUBTITLE = + "chart.bedheight_middle.section.shortsubtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.bedheight_middle.section.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.bedheight_middle.section.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Mittlere Sohlöhe"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "km"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "mittlere Sohlhöhen [müNN]"; + + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + /** + * Returns the default title for this chart. + * + * @return the default title for this chart. + */ + @Override + public String getDefaultChartTitle() { + Object[] args = new Object[] { + getRiverName() + }; + + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, args); + } + + + /** + * Get internationalized label for the x axis. + */ + @Override + protected String getDefaultXAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg( + I18N_XAXIS_LABEL, + I18N_XAXIS_LABEL_DEFAULT, + new Object[] { FLYSUtils.getRiver(flys).getName() }); + } + + + @Override + protected String getDefaultYAxisLabel(int index) { + String label = "default"; + + if (index == YAXIS.H.idx) { + label = getHAxisLabel(); + } + + return label; + } + + + /** + * Get internationalized label for the y axis. + */ + protected String getHAxisLabel() { + FLYSArtifact flys = (FLYSArtifact) master; + + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + /** + * Produce output. + * @param artifactAndFacet current facet. + * @param attr theme for facet + */ + public void doOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + String name = artifactAndFacet.getFacetName(); + + logger.debug("MiddleBedHeightGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + Facet facet = artifactAndFacet.getFacet(); + + if (facet == null) { + return; + } + + if (name.equals(MIDDLE_BED_HEIGHT_SINGLE) || name.equals(MIDDLE_BED_HEIGHT_EPOCH)) { + doHeightOut( + (MiddleBedHeightData) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (name.equals(MIDDLE_BED_HEIGHT_ANNOTATION)) { + doAnnotations( + (FLYSAnnotation) artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.AREA(name)) { + doArea( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints( + artifactAndFacet.getData(context), + artifactAndFacet, + attr, + visible, + YAXIS.H.idx); + } + else { + logger.warn("Unknown facet name: " + name); + return; + } + } + + + /** + * @param data A data object + * @param aandf The artifact and facet. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + */ + protected void doHeightOut( + MiddleBedHeightData data, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("MiddleBedHeightGenerator.doMainChannelOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getMiddleHeightsPoints(), true); + + addAxisSeries(series, YAXIS.H.idx, visible); + } + + + /** Look up the axis identifier for a given facet type. */ + public int axisIdxForFacet(String facetName) { + if (FacetTypes.IS.H(facetName)) { + return YAXIS.H.idx; + } + else { + logger.warn("Could not find axis for facet " + facetName); + return YAXIS.H.idx; + } + } + + + /** + * Do Area out. + * @param theme styling information. + * @param visible whether or not visible. + */ + protected void doArea( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + logger.debug("FlowVelocityGenerator.doArea"); + logger.warn("TODO: Implement FlowVelocityGenerator.doArea"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MiddleBedHeightInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * middle bed height curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MiddleBedHeightInfoGenerator +extends ChartInfoGenerator +{ + public MiddleBedHeightInfoGenerator() { + super(new MiddleBedHeightGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,42 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +/** + * An OutGenerator that generates reference curves. + */ +public class NormalizedReferenceCurveGenerator +extends ReferenceCurveGenerator +{ + /** House logger. */ + private static Logger logger = + Logger.getLogger(NormalizedReferenceCurveGenerator.class); + + public static final String I18N_NORMALIZED_CHART_TITLE = + "chart.normalized.reference.curve.title"; + + public static final String I18N_NORMALIZED_CHART_TITLE_DEFAULT = + "Reduzierte Bezugslinie"; + + public NormalizedReferenceCurveGenerator() { + } + + /** Get default chart title. */ + @Override + protected String getDefaultChartTitle() { + return msg( + I18N_NORMALIZED_CHART_TITLE, + I18N_NORMALIZED_CHART_TITLE_DEFAULT); + } + + @Override + protected String facetName() { + return REFERENCE_CURVE_NORMALIZED; + } + + @Override + protected boolean doNormalize() { + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific reference + * curves. + */ +public class NormalizedReferenceCurveInfoGenerator +extends ChartInfoGenerator +{ + public NormalizedReferenceCurveInfoGenerator() { + super(new NormalizedReferenceCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/OutGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,83 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.OutputStream; + +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.collections.FLYSArtifactCollection; + + +/** + * An OutGenerator is used to create a collected outputs of a list of Artifacts. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface OutGenerator { + + /** + * Initializes the OutGenerator with meta information which are necessary + * for the output generation. + * + * @param request The incomding request document. + * @param out The output stream. + * @param context The CallContext that provides further information and + * objects used for the output generation. + */ + void init(Document request, OutputStream out, CallContext context); + + /** + * This method is used to tell the OutGenerator which artifact is the master + * artifact which is used for special operations. + * + * @param master The master artifact. + */ + void setMasterArtifact(Artifact master); + + /** + * This method is used to set the Collection of the OutGenerator. + * + * @param collection A reference to the collection. + */ + void setCollection(FLYSArtifactCollection collection); + + /** + * Creates the output of an Artifact and appends that single output to the + * total output. + * + * @param bundle The Facet and artifact that provides information and data for the + * single output. + * @param attr A document that might contain some attributes used while + * producing the output. + * @param visible Specifies, if this output should be visible or not. + */ + void doOut(ArtifactAndFacet bundle, Document attr, boolean visible); + + /** + * Writes the collected output of all artifacts specified in the + * <i>request</i> (see init()) document to the OutputStream <i>out</i> (see + * init()). + */ + void generate() throws IOException; + + /** + * This method is used to set a <i>Settings</i> object for the <i>Output</i> + * that is produced by this <i>OutGenerator</i>. + * + * @param settings The <i>Settings</i> that might be used while + * <i>Output</i> creation. + */ + void setSettings(Settings settings); + + /** + * Returns the Settings for the Output produced by this OutGenerator. + * + * @return the Settings for the Output produced by this OutGenerator. + */ + Settings getSettings(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/OutputHelper.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,519 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.intevation.artifactdatabase.Backend; +import de.intevation.artifactdatabase.Backend.PersistentArtifact; +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.ClientProtocolUtils; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.model.ManagedDomFacet; +import de.intevation.flys.artifacts.model.ManagedFacet; +import de.intevation.flys.themes.Theme; +import de.intevation.flys.themes.ThemeFactory; + +public class OutputHelper { + /** The logger used in this class. */ + private static Logger log = Logger.getLogger(OutputHelper.class); + + protected String identifier; + + public OutputHelper(String identifier) { + this.identifier = identifier; + } + /** + * Creates a concrete output. + * + * @param generator The OutGenerator that creates the output. + * @param outputName The name of the requested output. + * @param attributes The collection's attributes for this concrete output + * type. + * @param context The context object. + */ + public void doOut( + OutGenerator generator, + String outName, + String facet, + Document attributes, + CallContext context) + throws IOException + { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("FLYSArtifactCollection.doOut: " + outName); + } + + ThemeList themeList = new ThemeList(attributes); + + int size = themeList.size(); + if (debug) { + log.debug("Output will contain " + size + " elements."); + } + + List<ArtifactAndFacet> dataProviders = + doBlackboardPass(themeList, context); + + try { + for (int i = 0; i < size; i++) { + ManagedFacet theme = themeList.get(i); + + if (theme == null) { + log.debug("Theme is empty - no output is generated."); + continue; + } + + String art = theme.getArtifact(); + String facetName = theme.getName(); + + if (debug) { + log.debug("Do output for..."); + log.debug("... artifact: " + art); + log.debug("... facet: " + facetName); + } + + if (outName.equals("export") && !facetName.equals(facet)) { + continue; + } + + // Skip invisible themes. + if (theme.getVisible() == 0) { + continue; + } + + if (outName.equals("sq_overview")) { + generator.doOut( + dataProviders.get(i), + attributes, + theme.getActive() == 1); + } + else { + generator.doOut( + dataProviders.get(i), + getFacetThemeFromAttribute( + art, + outName, + facetName, + theme.getDescription(), + theme.getIndex(), + context), + theme.getActive() == 1); + } + } + } + catch (ArtifactDatabaseException ade) { + log.error(ade, ade); + } + } + /** + * Returns the attribute that belongs to an artifact and facet stored in + * this collection. + * + * @param uuid The Artifact's uuid. + * @param outname The name of the requested output. + * @param facet The name of the requested facet. + * @param context The CallContext. + * + * @return an attribute in form of a document. + */ + protected Document getFacetThemeFromAttribute( + String uuid, + String outName, + String facet, + String pattern, + int index, + CallContext context) + throws ArtifactDatabaseException + { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "FLYSArtifactCollection.getFacetThemeFromAttribute(facet=" + + facet + ", index=" + index + ")"); + } + + + ArtifactDatabase db = context.getDatabase(); + CallMeta meta = context.getMeta(); + + FLYSContext flysContext = context instanceof FLYSContext + ? (FLYSContext) context + : (FLYSContext) context.globalContext(); + + Document attr = db.getCollectionItemAttribute(identifier, uuid, meta); + + if (attr == null) { + attr = initItemAttribute(uuid, facet, pattern, index, outName, context); + + if (attr == null) { + return null; + } + } + + if (debug) { + log.debug("Search attribute of collection item: " + uuid); + } + + Node tmp = (Node) XMLUtils.xpath( + attr, + "/art:attribute", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (tmp == null) { + log.warn("No attribute found. Operation failed."); + return null; + } + + if (debug) { + log.debug("Search theme for facet '" + facet + "' in attribute."); + } + + Map<String, String> vars = new HashMap<String, String>(); + vars.put("facet", facet); + vars.put("index", String.valueOf(index)); + + Node theme = (Node) XMLUtils.xpath( + tmp, + "art:themes/theme[@facet=$facet and @index=$index]", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE, + vars); + + if (theme == null) { + log.warn("Could not find the theme in attribute of: " + facet + " " + uuid); + + Theme t = getThemeForFacet( + uuid, facet, pattern, index, outName, context); + + if (t == null) { + log.warn("No theme found for facet: " + facet); + return null; + } + + addThemeToAttribute(uuid, attr, t, context); + theme = t.toXML().getFirstChild(); + } + + Document doc = XMLUtils.newDocument(); + doc.appendChild(doc.importNode(theme, true)); + + return doc; + } + /** + * Adds the theme of a facet to a CollectionItem's attribute. + * + * @param uuid The uuid of the artifact. + * @param attr The current attribute of an artifact. + * @param t The theme to add. + * @param context The CallContext. + */ + protected void addThemeToAttribute( + String uuid, + Document attr, + Theme t, + CallContext context) + { + log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid); + + if (t == null) { + log.warn("Theme is empty - cancel adding it to attribute!"); + return; + } + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + attr, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Node tmp = (Node) XMLUtils.xpath( + attr, + "/art:attribute", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (tmp == null) { + tmp = ec.create("attribute"); + attr.appendChild(tmp); + } + + Node themes = (Node) XMLUtils.xpath( + tmp, + "art:themes", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (themes == null) { + themes = ec.create("themes"); + tmp.appendChild(themes); + } + + themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true)); + + try { + setCollectionItemAttribute(uuid, attr, context); + } + catch (ArtifactDatabaseException e) { + // do nothing + log.warn("Cannot set attribute of item: " + uuid); + } + } + + /** + * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new + * value <i>attr</i>. + * + * @param uuid The uuid of the CollectionItem. + * @param attr The new attribute for the CollectionItem. + * @param context The CallContext. + */ + public void setCollectionItemAttribute( + String uuid, + Document attr, + CallContext context) + throws ArtifactDatabaseException + { + Document doc = ClientProtocolUtils.newSetItemAttributeDocument( + uuid, + attr); + + if (doc == null) { + log.warn("Cannot set item attribute: No attribute found."); + return; + } + + ArtifactDatabase db = context.getDatabase(); + CallMeta meta = context.getMeta(); + + db.setCollectionItemAttribute(identifier, uuid, doc, meta); + } + + + /** + * Show blackboard (context) to each facet and create a list of + * ArtifactAndFacets on the fly (with the same ordering as the passed + * ThemeList). + * @param themeList ThemeList to create a ArtifactAndFacetList along. + * @param context The "Blackboard". + */ + protected List<ArtifactAndFacet> doBlackboardPass( + ThemeList themeList, CallContext context + ) { + ArrayList<ArtifactAndFacet> dataProviders = + new ArrayList<ArtifactAndFacet>(); + int size = themeList.size(); + + try { + // Collect all ArtifactAndFacets for blackboard pass. + for (int i = 0; i < size; i++) { + ManagedFacet theme = themeList.get(i); + if (theme == null) { + log.warn("A ManagedFacet in ThemeList is null."); + continue; + } + String uuid = theme.getArtifact(); + Artifact artifact = getArtifact(uuid, context); + FLYSArtifact flys = (FLYSArtifact) artifact; + + ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet( + artifact, + flys.getNativeFacet(theme)); + + // XXX HELP ME PLEASE + artifactAndFacet.setFacetDescription(theme.getDescription()); + + // Show blackboard to facet. + artifactAndFacet.register(context); + + // Add to themes. + dataProviders.add(i, artifactAndFacet); + } + } + catch (ArtifactDatabaseException ade) { + log.error("ArtifactDatabaseException!", ade); + } + + return dataProviders; + } + /** + * Returns a concrete Artifact of this collection specified by its uuid. + * + * @param uuid The Artifact's uuid. + * @param context The CallContext. + * + * @return an Artifact. + */ + protected Artifact getArtifact(String uuid, CallContext context) + throws ArtifactDatabaseException + { + log.debug("FLYSArtifactCollection.getArtifact"); + + Backend backend = Backend.getInstance(); + PersistentArtifact persistent = backend.getArtifact(uuid); + + return persistent != null ? persistent.getArtifact() : null; + } + + /** + * Initializes the attribute of an collection item with the theme of a + * specific facet. + * + * @param uuid The uuid of an artifact. + * @param facet The name of a facet. + * @param context The CallContext. + * + * @param the new attribute. + */ + protected Document initItemAttribute( + String uuid, + String facet, + String pattern, + int index, + String outName, + CallContext context) + { + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("FLYSArtifactCollection.initItemAttribute"); + } + + Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context); + + if (t == null) { + log.info("Could not find theme for facet. Cancel initialization."); + return null; + } + + Document attr = XMLUtils.newDocument(); + addThemeToAttribute(uuid, attr, t, context); + + if (debug) { + log.debug("initItemAttribute for facet " + facet + ": " + + XMLUtils.toString(attr)); + } + + return attr; + } + + /** + * Returns the theme of a specific facet. + * + * @param uuid The uuid of an artifact. + * @param facet The name of the facet. + * @param context The CallContext object. + * + * @return the desired theme. + */ + protected Theme getThemeForFacet( + String uuid, + String facet, + String pattern, + int index, + String outName, + CallContext context) + { + log.info("FLYSArtifactCollection.getThemeForFacet: " + facet); + + FLYSContext flysContext = context instanceof FLYSContext + ? (FLYSContext) context + : (FLYSContext) context.globalContext(); + + // Push artifact in flysContext. + ArtifactDatabase db = context.getDatabase(); + try { + FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid); + log.debug("Got raw artifact"); + flysContext.put(FLYSContext.ARTIFACT_KEY, artifact); + } + catch (ArtifactDatabaseException dbe) { + log.error("Exception caught when trying to get art.", dbe); + } + + Theme t = ThemeFactory.getTheme( + flysContext, + facet, + pattern, + outName, + "default"); + + if (t != null) { + log.debug("found theme for facet '" + facet + "'"); + t.setFacet(facet); + t.setIndex(index); + } + else { + log.warn("unable to find theme for facet '" + facet + "'"); + } + + return t; + } + + /** + * Inner class to structure/order the themes of a chart. + */ + private static class ThemeList { + private Logger logger = Logger.getLogger(ThemeList.class); + protected Map<Integer, ManagedFacet> themes; + + public ThemeList(Document output) { + themes = new HashMap<Integer, ManagedFacet>(); + parse(output); + } + + protected void parse(Document output) { + NodeList themeList = (NodeList) XMLUtils.xpath( + output, + "art:output/art:facet", + XPathConstants.NODESET, + ArtifactNamespaceContext.INSTANCE); + + int num = themeList != null ? themeList.getLength() : 0; + + logger.debug("Output has " + num + " elements."); + + if (num == 0) { + return; + } + + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + for (int i = 0; i < num; i++) { + Element theme = (Element) themeList.item(i); + + ManagedDomFacet facet = new ManagedDomFacet(theme); + themes.put(Integer.valueOf(facet.getPosition()-1), facet); + } + } + + public ManagedFacet get(int idx) { + return themes.get(Integer.valueOf(idx)); + } + + public int size() { + return themes.size(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,370 @@ +package de.intevation.flys.exports; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WWQQ; +import de.intevation.flys.artifacts.model.WWQQJRDataSource; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; + +import java.io.IOException; +import java.io.OutputStream; + +import java.text.DateFormat; +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +/** + * (CSV)Exporter for Reference Curves. + */ +public class ReferenceCurveExporter extends AbstractExporter { + + /** The logger used in this exporter. */ + private static Logger logger = Logger.getLogger(ReferenceCurveExporter.class); + + public static final String RC_CSV_KM_HEADER = + "export.reference_curve.csv.header.km"; + + public static final String RC_CSV_W_CM_HEADER = + "export.reference_curve.csv.header.w.cm"; + + public static final String RC_CSV_W_M_HEADER = + "export.reference_curve.csv.header.w.m"; + + public static final String RC_CSV_Q_HEADER = + "export.reference_curve.csv.header.w.q"; + + public static final String CSV_LOCATION_HEADER = + "export.waterlevel.csv.header.location"; + + public static final String DEFAULT_CSV_LOCATION_HEADER = "Lage"; + + public static final String RC_DEFAULT_CSV_KM_HEADER = "Fluss-Km"; + public static final String RC_DEFAULT_CSV_W_M_HEADER = "W (m + NHN)"; + public static final String RC_DEFAULT_CSV_W_CM_HEADER = "W (cm am Pegel)"; + public static final String RC_DEFAULT_CSV_Q_HEADER = "gleichw. Q (m\u00b3/s)"; + + public static final String PDF_HEADER_MODE = "export.reference_curve.pdf.mode"; + public static final String JASPER_FILE = "export.reference_curve.pdf.file"; + public static final String JASPER_FILE_GAUGE = "export.reference_curve.pdf.file.gauge"; + public static final String JASPER_FILE_GAUGE_END = "export.reference_curve.pdf.file.gauge.end"; + public static final String JASPER_FILE_GAUGE_START_END = "export.reference_curve.pdf.file.gauge.start.end"; + + /** The storage that contains all WKms objects for the different facets. */ + protected List<WWQQ[]> data; + + protected boolean startAtGauge = false; + + protected boolean endAtGauge = false; + + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("ReferenceCurveExporter.init"); + + super.init(request, out, context); + + this.data = new ArrayList<WWQQ[]>(); + } + + + /** + * Genereate data in csv format. + */ + @Override + public void generate() + throws IOException + { + logger.debug("ReferenceCurveExporter.generate"); + + if (facet == null) { + throw new IOException("invalid (null) facet for exporter"); + } + else if (facet.equals(AbstractExporter.FACET_CSV)) { + generateCSV(); + } + else if (facet.equals(AbstractExporter.FACET_PDF)) { + generatePDF(); + } + else { + throw new IOException("invalid facet (" + facet + ") for exporter"); + } + } + + + /** + * Adds given data. + * @param d A CalculationResult with WWQQ[]. + */ + @Override + protected void addData(Object d) { + logger.debug("ReferenceCurveExporter.addData"); + + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WWQQ []) { + WWQQ[] wwqqs = (WWQQ []) d; + for (WWQQ wwqq: wwqqs) { + if (wwqq.startAtGauge()) { + startAtGauge = true; + } + // TODO this one probably has to be inverted. + if (wwqq.endAtGauge()) { + endAtGauge = true; + } + } + data.add(wwqqs); + logger.debug("ReferenceCurveExporter.addData wwqq[]."); + } + else { + logger.warn("ReferenceCurveExporter.addData/1 unknown type (" + + d + ")."); + } + } + else { + logger.warn("ReferenceCurveExporter.addData/2 unknown type (" + + d + ")."); + } + } + + + /** + * Lets writer write all data (including header). + * @param writer Writer to write data with. + */ + @Override + protected void writeCSVData(CSVWriter writer) { + logger.debug("ReferenceCurveExporter.writeData"); + + writeCSVHeader(writer); + + for (WWQQ[] tmp: data) { + for (WWQQ ww: tmp) { + wWQQ2CSV(writer, ww); + } + } + } + + + /** + * Lets csvwriter write the header (first line in file). + * @param writer Writer to write header with. + */ + protected void writeCSVHeader(CSVWriter writer) { + logger.info("ReferenceCurveExporter.writeCSVHeader"); + + StepCSVWriter stepWriter = new StepCSVWriter(); + stepWriter.setCSVWriter(writer); + + stepWriter.addNexts( + msg(RC_CSV_KM_HEADER, RC_DEFAULT_CSV_KM_HEADER), + msg(RC_CSV_W_M_HEADER, RC_DEFAULT_CSV_W_M_HEADER) + ); + if (startAtGauge) { + stepWriter.addNext( + msg(RC_CSV_W_CM_HEADER, RC_DEFAULT_CSV_W_CM_HEADER)); + } + stepWriter.addNexts( + msg(RC_CSV_Q_HEADER, RC_DEFAULT_CSV_Q_HEADER), + msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER), + msg(RC_CSV_KM_HEADER, RC_DEFAULT_CSV_KM_HEADER), + msg(RC_CSV_W_M_HEADER, RC_DEFAULT_CSV_W_M_HEADER) + ); + if (endAtGauge) { + stepWriter.addNext( + msg(RC_CSV_W_CM_HEADER, RC_DEFAULT_CSV_W_CM_HEADER) + ); + } + stepWriter.addNexts( + msg(RC_CSV_Q_HEADER, RC_DEFAULT_CSV_Q_HEADER), + msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER) + ); + + stepWriter.flush(); + } + + + protected void wWQQ2CSV(CSVWriter writer, WWQQ ww) { + logger.debug("ReferenceCurveExporter.wWQQ2CSV"); + + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + int size = ww.size(); + + FLYSArtifact flys = (FLYSArtifact) master; + + StepCSVWriter stepWriter = new StepCSVWriter(); + stepWriter.setCSVWriter(writer); + + String startLocationDescription = FLYSUtils.getLocationDescription( + flys, ww.getStartKm()); + + String endLocationDescription = FLYSUtils.getLocationDescription( + flys, ww.getEndKm()); + + for (int i = 0; i < size; i ++) { + stepWriter.addNexts(kmf.format(ww.getStartKm())); + stepWriter.addNext(wf.format(ww.getW1(i))); + if (startAtGauge) { + stepWriter.addNext(wf.format(ww.getRelHeight1Cm(i))); + } + stepWriter.addNexts( + qf.format(ww.getQ1(i)), // "Q" + startLocationDescription, + kmf.format(ww.getEndKm()) + ); + stepWriter.addNext(wf.format(ww.getW2(i))); + if (endAtGauge) { + if (ww.endAtGauge()) { + stepWriter.addNext(wf.format(ww.getRelHeight2Cm(i))); + } + else { + stepWriter.addNext("-"); + } + } + stepWriter.addNexts( + qf.format(ww.getQ2(i)), // "Q" + endLocationDescription + ); + stepWriter.flush(); + } + } + + + @Override + protected void writePDF(OutputStream out) { + WWQQJRDataSource source = createJRData(); + + String filename = JASPER_FILE; + if (startAtGauge && endAtGauge) { + filename = JASPER_FILE_GAUGE_START_END; + } + else if (startAtGauge) { + filename = JASPER_FILE_GAUGE; + } + else if (endAtGauge) { + filename = JASPER_FILE_GAUGE_END; + } + + String jasperFile = Resources.getMsg( + context.getMeta(), + filename, + "/jasper/reference_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + } + + protected WWQQJRDataSource createJRData() { + WWQQJRDataSource source = new WWQQJRDataSource(); + + addMetaData(source); + + for (WWQQ[] tmp: data) { + for (WWQQ ww: tmp) { + addWWQQData(source, ww); + } + } + return source; + } + + + protected void addMetaData(WWQQJRDataSource source) { + CallMeta meta = context.getMeta(); + + WINFOArtifact flys = (WINFOArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "Reference Curve")); + } + + + protected void addWWQQData(WWQQJRDataSource source, WWQQ ww) { + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + int size = ww.size(); + + FLYSArtifact flys = (FLYSArtifact) master; + + String startLocationDescription = FLYSUtils.getLocationDescription( + flys, ww.getStartKm()); + + String endLocationDescription = FLYSUtils.getLocationDescription( + flys, ww.getEndKm()); + + for (int i = 0; i < size; i ++) { + String start = "-"; + String end = "-"; + if (startAtGauge) { + start = wf.format(ww.getRelHeight1Cm(i)); + } + if (ww.endAtGauge()) { + end = wf.format(ww.getRelHeight2Cm(i)); + } + source.addData(new String[] { + kmf.format(ww.getStartKm()), + startLocationDescription, + wf.format(ww.getW1(i)), + qf.format(ww.getQ1(i)), // "Q" + kmf.format(ww.getEndKm()), + endLocationDescription, + wf.format(ww.getW2(i)), + qf.format(ww.getQ2(i)), // "Q" + start, + end + }); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,271 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WW; +import de.intevation.flys.artifacts.model.WW.ApplyFunctionIterator; +import de.intevation.flys.artifacts.model.WWAxisTypes; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.utils.Formatter; + +import java.awt.geom.Point2D; + +import org.apache.log4j.Logger; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.NumberTickUnit; +import org.jfree.chart.axis.TickUnits; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + +/** + * An OutGenerator that generates reference curves. + */ +public class ReferenceCurveGenerator +extends XYChartGenerator +implements FacetTypes +{ + public static enum YAXIS { + W(0); + + public int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** House logger. */ + private static Logger logger = + Logger.getLogger(ReferenceCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.reference.curve.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.reference.curve.subtitle"; + + public static final String I18N_X_AXIS_IN_CM = + "chart.reference.curve.x.axis.in.cm"; + + public static final String I18N_X_AXIS_IN_M = + "chart.reference.curve.x.axis.in.m"; + + public static final String I18N_Y_AXIS_IN_CM = + "chart.reference.curve.y.axis.in.cm"; + + public static final String I18N_Y_AXIS_IN_M = + "chart.reference.curve.y.axis.in.m"; + + public static final String I18N_CHART_TITLE_DEFAULT = + "Bezugslinie"; + + + public ReferenceCurveGenerator() { + } + + /** + * Create Axis for given index. + * @return axis with according internationalized label. + */ + @Override + protected NumberAxis createYAxis(int index) { + NumberAxis axis = super.createYAxis(index); + axis.setAutoRangeIncludesZero(false); + return axis; + } + + + /** Get default chart title. */ + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + @Override + protected String getDefaultChartSubtitle() { + Object[] args = new Object[] { + getRiverName(), + }; + + return msg(I18N_CHART_SUBTITLE, "", args); + } + + + /** True if axis is in cm (because at gauge). */ + protected boolean getInCm(int index) { + Object obj = context.getContextValue("reference.curve.axis.scale"); + return obj instanceof WWAxisTypes && ((WWAxisTypes)obj).getInCm(index); + } + + + /** Get Label for X-axis (W). */ + @Override + protected String getDefaultXAxisLabel() { + return msg(getInCm(0) ? I18N_X_AXIS_IN_CM : I18N_X_AXIS_IN_M); + } + + + /** + * Get Label for primary and other Y Axes. + * @param index Axis-Index (0-based). + */ + @Override + protected String getDefaultYAxisLabel(int index) { + return msg(getInCm(1) ? I18N_Y_AXIS_IN_CM : I18N_Y_AXIS_IN_M); + } + + protected String facetName() { + return REFERENCE_CURVE; + } + + + /** + * Called for each facet/them in the out mapped to this generator. + * @param artifactFacet artifact and facet for this theme. + * @param theme styling info. + * @param visible Whether or not the theme is visible. + */ + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document theme, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + + logger.debug("ReferenceCurveGenerator.doOut: " + name); + + if (name == null || name.length() == 0) { + logger.error("No facet given. Cannot create dataset."); + return; + } + + if (name.equals(facetName())) { + doReferenceOut(artifactFacet.getData(context), theme, visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints( + artifactFacet.getData(context), + artifactFacet, + theme, + visible, + YAXIS.W.idx); + } + else if (name.equals(RELATIVE_POINT)) { + doPointOut( + (Point2D) artifactFacet.getData(context), + artifactFacet, + theme, + visible); + } + else if (name.equals(MAINVALUES_W)) { + doAnnotations( + ((FLYSAnnotation) artifactFacet.getData(context)).flipStickyAxis(), + artifactFacet, + theme, + visible); + + } + else { + logger.warn("Unknown facet name: " + name); + } + } + + protected boolean doNormalize() { + return false; + } + + + /** Register DataSeries with (maybe transformed) points. */ + public void doReferenceOut( + Object data, + Document theme, + boolean visible + ) { + WW ww = (WW)data; + + Object obj = context.getContextValue("reference.curve.axis.scale"); + + WWAxisTypes wwat = obj instanceof WWAxisTypes + ? (WWAxisTypes)obj + : new WWAxisTypes(ww); + + ApplyFunctionIterator iter = wwat.transform(ww, doNormalize()); + + XYSeries series = new StyledXYSeries( + ww.getName(), false, theme); + + double [] values = new double[2]; + + while (iter.hasNext()) { + iter.next(values); + series.add(values[0], values[1], false); + } + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + // TODO resolve duplicate in DurationCurveGenerator + protected void doPointOut( + Point2D point, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ){ + logger.debug("ReferenceCurveGenerator.doPointOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + series.add(point.getX(), point.getY()); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** Set the tick units for given axis. */ + protected void setAxisTickUnit(double tick, ValueAxis axis) { + TickUnits units = new TickUnits(); + units.add(new NumberTickUnit(tick, Formatter.getWaterlevelW(context))); + axis.setStandardTickUnits(units); + axis.setAutoTickUnitSelection(true); + } + + @Override + protected void localizeDomainAxis(ValueAxis domainAxis) { + super.localizeDomainAxis(domainAxis); + if (getInCm(0)) { + setAxisTickUnit(100d, domainAxis); + } + else { + setAxisTickUnit(1d, domainAxis); + } + } + + + @Override + protected void localizeRangeAxis(ValueAxis rangeAxis) { + super.localizeRangeAxis(rangeAxis); + setAxisTickUnit(1d, rangeAxis); + } + + /** Get Walker to iterate over all axes. */ + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + /** Get number of items. */ + @Override + public int length() { + return YAXIS.values().length; + } + + /** Get identifier for this index. */ + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ReferenceCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific reference + * curves. + */ +public class ReferenceCurveInfoGenerator +extends ChartInfoGenerator +{ + public ReferenceCurveInfoGenerator() { + super(new ReferenceCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ReportGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,96 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.Settings; + +import de.intevation.flys.artifacts.model.Calculation; +import de.intevation.flys.collections.FLYSArtifactCollection; + +import org.w3c.dom.Document; + +public class ReportGenerator +implements OutGenerator +{ + private static Logger logger = Logger.getLogger(ReportGenerator.class); + + protected Document result; + protected OutputStream out; + protected CallContext context; + + public ReportGenerator() { + } + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("init"); + this.out = out; + this.context = context; + result = null; + } + + @Override + public void setMasterArtifact(Artifact master) { + // not needed + } + + @Override + public void setCollection(FLYSArtifactCollection collection) { + // not needed + } + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document attr, + boolean visible + ) { + logger.debug("doOut"); + Facet facet = artifactFacet.getFacet(); + if (facet != null) { + Calculation report = (Calculation) artifactFacet.getData(context); + if (result == null) { + result = XMLUtils.newDocument(); + report.toXML(result, context.getMeta()); + } + } + } + + @Override + public void generate() throws IOException { + logger.debug("generate"); + XMLUtils.toStream(result != null + ? result + : XMLUtils.newDocument(), out); + } + + + /** + * Returns an instance of <i>EmptySettings</i> currently! + * + * @return an instance of <i>EmptySettings</i>. + */ + public Settings getSettings() { + return new EmptySettings(); + } + + + /** + * This method is not implemented. Override it in subclasses if those need a + * <i>Settings</i> object. + */ + public void setSettings(Settings settings) { + // do nothing + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StepCSVWriter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,51 @@ +package de.intevation.flys.exports; + +import au.com.bytecode.opencsv.CSVWriter; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Class to overcome shortcoming of CSVWriter to accept String-Arrays only. + * The StepCSVWriter buffers incoming values, such that rows in a csv can be + * created more dynamically. Do not forget to call flush(). + */ +public class StepCSVWriter { + + /** Writer to use when calling flush. */ + CSVWriter writer = null; + /** Buffer of strings (values). */ + ArrayList<String> buffer; + + + /** Trivial constructor. */ + public StepCSVWriter() { + buffer = new ArrayList<String>(); + } + + + /** Set writer. */ + public void setCSVWriter(CSVWriter writer) { + this.writer = writer; + } + + + /** Add a value to next flush. */ + public void addNext(String value) { + buffer.add(value); + } + + + /** Add many values to next flush. */ + public void addNexts(String ... values) { + buffer.addAll(Arrays.asList(values)); + } + + + /** Write the row with csvwriter. */ + public void flush() { + writer.writeNext(buffer.toArray(new String[buffer.size()])); + buffer.clear(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StringAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,37 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class StringAttribute extends VisibleAttribute { + + + public StringAttribute(String name, String value, boolean visible) { + super(name, value, visible); + } + + + /** + * Calls VisibleAttribute.toXML() and appends afterwards an attribute + * <i>type</i> with value <i>string</i>. + * + * @param parent The parent Node. + * + * @return the new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("type", "string"); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,220 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +import org.jfree.data.xy.XYSeries; + +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WWQQ; + +/** + * Helper to create and modify StyledXYSeries. + */ +public class StyledSeriesBuilder { + + /** + * JFreeChart and the area calculation will fail if we use Double.INFINITY + * or Double.MAX_VALUE (probably because these are really used in + * calculations). We define and use a more handy value instead. + */ + final static double BIG_DOUBLE_VALUE = 1234567d; + + private static final Logger logger = Logger.getLogger + (StyledSeriesBuilder.class); + + + /** + * Trivial, hidden constructor. + */ + private StyledSeriesBuilder() { + } + + + /** + * Add points to series. + * + * @param series Series to add points to. + * @param points Points to add to series, points[0] to 1st dim, points[1] + * to 2nd dim. + * @param skipNANs if true, skip NAN values in points parameter. + */ + public static void addPoints(XYSeries series, double[][] points, boolean skipNANs) { + if (points == null || points.length <= 1) { + return; + } + double [] xPoints = points[0]; + double [] yPoints = points[1]; + for (int i = 0; i < xPoints.length; i++) { + if (skipNANs && + (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) { + logger.warn ("Skipping NaN in StyledSeriesBuilder."); + continue; + } + series.add(xPoints[i], yPoints[i], false); + } + } + + + /** + * Add points to series (km to 1st dim, w to 2nd dim). + * + * @param series Series to add points to. + * @param wkms WKms to add to series. + */ + public static void addPoints(XYSeries series, WKms wkms) { + if (wkms == null) { + return; + } + + int size = wkms.size(); + + for (int i = 0; i < size; i++) { + series.add(wkms.getKm(i), wkms.getW(i), false); + } + } + + + /** + * Add points to dataset with an offset (shift all points by given amount). + * @param series series to add data to. + * @param wkms WKms of which the Ws will be shifted. + * @param off the offset. + */ + public static void addUpperBand(XYSeries series, WKms wkms, double off) { + if (wkms == null) { + return; + } + + int size = wkms.size(); + + for (int i = 0; i < size; i++) { + series.add(wkms.getKm(i), wkms.getW(i)+off, false); + } + } + + + /** + * Add points to dataset with an offset (shift all points 'down' by given + * amount). + * @param series series to add data to. + * @param wkms WKms of which the Ws will be shifted. + * @param off the offset. + */ + public static void addLowerBand(XYSeries series, WKms wkms, double off) { + addUpperBand(series, wkms, -off); + } + + + /** + * Add points to series (km to 1st dim, q to 2nd dim). + * + * @param series Series to add points to. + * @param wqkms WQKms to add to series. + */ + public static void addPointsKmQ(XYSeries series, WQKms wqkms) { + if (wqkms == null) { + return; + } + + int size = wqkms.size(); + + for (int i = 0; i < size; i++) { + series.add(wqkms.getKm(i), wqkms.getQ(i), false); + } + } + + + /** + * Add points to series (km to 1st dim, q to 2nd dim), adding points + * to achieve a step-like curve. + * + * @param series Series to add points to. + * @param wqkms WQKms to add to series. + */ + public static void addStepPointsKmQ(XYSeries series, WQKms wqkms) { + if (wqkms == null) { + return; + } + + int size = wqkms.size(); + + for (int i = 0; i < size; i++) { + if (i==0) { + series.add(wqkms.getKm(i), wqkms.getQ(i), false); + } + else { + //Add two points. + double halveX = (wqkms.getKm(i-1) + wqkms.getKm(i)) / 2d; + series.add(halveX, wqkms.getQ(i-1)); + series.add(halveX, wqkms.getQ(i)); + } + if (i == size-1) { + series.add(wqkms.getKm(i), wqkms.getQ(i), false); + } + } + } + + + /** + * Add points to series (q to 1st dim, w to 2nd dim). + * + * @param series Series to add points to. + * @param wqkms WQKms to add to series. + */ + public static void addPointsQW(XYSeries series, WQKms wqkms) { + if (wqkms == null) { + return; + } + + int size = wqkms.size(); + + for (int i = 0; i < size; i++) { + series.add(wqkms.getQ(i), wqkms.getW(i)); + } + } + + + /** + * Add points to series (q to 1st dim, w to 2nd dim). + * + * @param series Series to add points to. + * @param wwqq WWQQ to add to series. + */ + public static void addPoints(XYSeries series, WWQQ wwqq) { + if (wwqq == null) { + return; + } + + int size = wwqq.size(); + + for (int i = 0; i < size; i++) { + series.add(wwqq.getW1(i), wwqq.getW2(i)); + } + } + + + /** + * Create a Series such that an infinitely big area can be filled + * between the newly created and the given series. + */ + public static XYSeries createGroundAtInfinity(XYSeries series) { + XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */ "INF"); + ground.add(series.getMinX(), -BIG_DOUBLE_VALUE); + ground.add(series.getMaxX(), -BIG_DOUBLE_VALUE); + return ground; + } + + + /** + * Create a Series such that an infinitely big area can be filled + * between the newly created and the given series. + */ + public static XYSeries createCeilingAtInfinity(XYSeries series) { + XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */ "INF"); + ground.add(series.getMinX(), BIG_DOUBLE_VALUE); + ground.add(series.getMaxX(), BIG_DOUBLE_VALUE); + return ground; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,826 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.jfree.DoubleBounds; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledTimeSeries; +import de.intevation.flys.jfree.TimeBounds; + +import java.awt.Color; +import java.awt.Font; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.ImageIcon; + +import org.apache.log4j.Logger; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.annotations.XYAnnotation; +import org.jfree.chart.annotations.XYImageAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.Range; +import org.jfree.data.general.Series; +import org.jfree.data.time.Day; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.xy.XYDataset; +import org.jfree.ui.Layer; +import org.json.JSONArray; +import org.json.JSONException; +import org.w3c.dom.Document; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class TimeseriesChartGenerator extends ChartGenerator { + + + /** + * Inner class TimeseriesAxisDataset stores TimeSeriesCollection. + */ + public class TimeseriesAxisDataset implements AxisDataset { + + protected int axisSymbol; + + protected List<TimeSeriesCollection> datasets; + + protected Range range; + + protected int plotAxisIndex; + + public TimeseriesAxisDataset(int axisSymbol) { + this.axisSymbol = axisSymbol; + this.datasets = new ArrayList<TimeSeriesCollection>(); + } + + + @Override + public void addDataset(XYDataset dataset) { + if (!(dataset instanceof TimeSeriesCollection)) { + logger.warn("Skip non TimeSeriesCollection dataset."); + return; + } + + TimeSeriesCollection tsc = (TimeSeriesCollection) dataset; + + datasets.add(tsc); + mergeRanges(tsc); + } + + + @Override + public XYDataset[] getDatasets() { + return datasets.toArray(new XYDataset[datasets.size()]); + } + + + @Override + public boolean isEmpty() { + return datasets.isEmpty(); + } + + + @Override + public void setRange(Range range) { + this.range = range; + } + + + @Override + public Range getRange() { + return range; + } + + + @Override + public void setPlotAxisIndex(int plotAxisIndex) { + this.plotAxisIndex = plotAxisIndex; + } + + + @Override + public int getPlotAxisIndex() { + return plotAxisIndex; + } + + + @Override + public boolean isArea(XYDataset dataset) { + logger.warn("This AxisDataset doesn't support Areas yet!"); + return false; + } + + + protected void mergeRanges(TimeSeriesCollection dataset) { + logger.debug("Range before merging: " + range); + Range subRange = null; + + // Determine min/max of range axis. + for (int i = 0; i < dataset.getSeriesCount(); i++) { + if (dataset.getSeries(i).getItemCount() == 0) { + continue; + } + double min = Double.MAX_VALUE; + double max = -Double.MAX_VALUE; + TimeSeries series = dataset.getSeries(i); + for (int j = 0; j < series.getItemCount(); j++) { + double tmp = series.getValue(j).doubleValue(); + min = tmp < min ? tmp : min; + max = tmp > max ? tmp : max; + } + if (subRange != null) { + subRange = new Range( + min < subRange.getLowerBound() ? + min : subRange.getLowerBound(), + max > subRange.getUpperBound() ? + max : subRange.getUpperBound()); + } + else { + subRange = new Range(min, max); + } + } + + // Avoid merging NaNs, as they take min/max place forever. + if (subRange == null || + Double.isNaN(subRange.getLowerBound()) || + Double.isNaN(subRange.getUpperBound())) { + return; + } + if (range == null) { + range = subRange; + return; + } + range = Range.combine(range, subRange); + } + + } // end of TimeseriesAxisDataset class + + protected List<Marker> domainMarker; + + protected List<Marker> valueMarker; + + protected Map<String, String> attributes; + + protected boolean domainZeroLineVisible; + + private static final Logger logger = + Logger.getLogger(TimeseriesChartGenerator.class); + + public static final int AXIS_SPACE = 5; + + protected Map<Integer, Bounds> xBounds; + + protected Map<Integer, Bounds> yBounds; + + + /** + * The default constructor that initializes internal datastructures. + */ + public TimeseriesChartGenerator() { + super(); + + xBounds = new HashMap<Integer, Bounds>(); + yBounds = new HashMap<Integer, Bounds>(); + domainMarker = new ArrayList<Marker>(); + valueMarker = new ArrayList<Marker>(); + attributes = new HashMap<String, String>(); + } + + + + @Override + public JFreeChart generateChart() { + logger.info("Generate Timeseries Chart."); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + getChartTitle(), + getXAxisLabel(), + getYAxisLabel(0), + null, + isLegendVisible(), + false, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + + chart.setBackgroundPaint(Color.WHITE); + plot.setBackgroundPaint(Color.WHITE); + + addSubtitles(chart); + adjustPlot(plot); + addDatasets(plot); + adjustAxes(plot); + addDomainAxisMarker(plot); + addValueAxisMarker(plot); + adaptZoom(plot); + + applySeriesAttributes(plot); + addAnnotationsToRenderer(plot); + addLogo(plot); + aggregateLegendEntries(plot); + return chart; + } + + + /** + * Return left most data points x value (on first axis). + * Shortcut, especially to be overridden in (LS) charts where + * axis could be inverted. + */ + protected double getLeftX() { + return (Long)getXBounds(0).getLower(); + } + + + /** + * Return right most data points x value (on first axis). + * Shortcut, especially to be overridden in (LS) charts where + * axis could be inverted. + */ + protected double getRightX() { + return (Long)getXBounds(0).getUpper(); + } + + + /** + * Add a logo as background annotation to plot. + * Copy from XYChartGenerator. + */ + protected void addLogo(XYPlot plot) { + String logo = showLogo(); + if (logo == null) { + logger.debug("No logo to show chosen"); + return; + } + + ImageIcon imageIcon = null; + if (logo.equals("none")) { + return; + } + /* + If you want to add images, remember to change code in these places: + flys-artifacts: + XYChartGenerator.java + Timeseries*Generator.java and + in the flys-client projects Chart*Propert*Editor.java. + Also, these images have to be put in + flys-artifacts/src/main/resources/images/ + flys-client/src/main/webapp/images/ + */ + java.net.URL imageURL; + if (logo.equals("Intevation")) { + imageURL = XYChartGenerator.class.getResource("/images/intevation.png"); + } + else { // TODO else if ... + imageURL = XYChartGenerator.class.getResource("/images/bfg_logo.gif"); + } + imageIcon = new ImageIcon(imageURL); + double xPos = 0d, yPos = 0d; + + String placeh = logoHPlace(); + String placev = logoVPlace(); + + if (placev == null || placev.equals("none")) { + placev = "top"; + } + if (placev.equals("top")) { + yPos = (Double)getYBounds(0).getUpper(); + } + else if (placev.equals("bottom")) { + yPos = (Double)getYBounds(0).getLower(); + } + else if (placev.equals("center")) { + yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-v value: " + placev); + } + + if (placeh == null || placeh.equals("none")) { + placeh = "center"; + } + if (placeh.equals("left")) { + xPos = getLeftX(); + } + else if (placeh.equals("right")) { + xPos = getRightX(); + } + else if (placeh.equals("center")) { + xPos = ((Long)getXBounds(0).getUpper() + (Long)getXBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-h value: " + placeh); + } + + logger.debug("logo position: " + xPos + "/" + yPos); + + org.jfree.ui.RectangleAnchor anchor + = org.jfree.ui.RectangleAnchor.TOP; + if (placev.equals("top")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.TOP; + } + } + else if (placev.equals("bottom")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM; + } + } + else if (placev.equals("center")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.CENTER; + } + } + + XYAnnotation xyannotation = + new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor); + plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND); + } + + + @Override + protected Series getSeriesOf(XYDataset dataset, int idx) { + return ((TimeSeriesCollection) dataset).getSeries(idx); + } + + + /** + * This method creates new instances of TimeseriesAxisDataset. + * + * @param idx The symbol for the new TimeseriesAxisDataset. + */ + @Override + protected AxisDataset createAxisDataset(int idx) { + logger.debug("Create a new AxisDataset for index: " + idx); + return new TimeseriesAxisDataset(idx); + } + + + @Override + protected void combineXBounds(Bounds bounds, int index) { + if (bounds != null) { + Bounds old = getXBounds(index); + + if (old != null) { + bounds = bounds.combine(old); + } + + setXBounds(index, bounds); + } + } + + + @Override + protected void combineYBounds(Bounds bounds, int index) { + if (bounds != null) { + Bounds old = getYBounds(index); + + if (old != null) { + bounds = bounds.combine(old); + } + + setYBounds(index, bounds); + } + } + + + // TODO REPLACE THIS METHOD WITH getBoundsForAxis(index) + @Override + public Range[] getRangesForAxis(int index) { + // TODO + Bounds[] bounds = getBoundsForAxis(index); + + return new Range[] { + new Range( + bounds[0].getLower().doubleValue(), + bounds[0].getUpper().doubleValue()), + new Range( + bounds[1].getLower().doubleValue(), + bounds[1].getUpper().doubleValue()) + }; + } + + + @Override + public Bounds getXBounds(int axis) { + return xBounds.get(axis); + } + + + @Override + protected void setXBounds(int axis, Bounds bounds) { + xBounds.put(axis, bounds); + } + + + @Override + public Bounds getYBounds(int axis) { + return yBounds.get(axis); + } + + + @Override + protected void setYBounds(int axis, Bounds bounds) { + if (bounds != null) { + yBounds.put(axis, bounds); + } + } + + + public Bounds[] getBoundsForAxis(int index) { + logger.debug("Return x and y bounds for axis at: " + index); + + Bounds rx = getXBounds(Integer.valueOf(index)); + Bounds ry = getYBounds(Integer.valueOf(index)); + + if (rx == null) { + logger.warn("Range for x axis not set." + + " Using default values: 0 - 1."); + rx = new TimeBounds(0l, 1l); + } + + if (ry == null) { + logger.warn("Range for y axis not set." + + " Using default values: 0 - 1."); + ry = new DoubleBounds(0l, 1l); + } + + logger.debug("X Bounds at index " + index + " is: " + rx); + logger.debug("Y Bounds at index " + index + " is: " + ry); + + return new Bounds[] {rx, ry}; + } + + + /** Get (zoom)values from request. */ + public Bounds getDomainAxisRange() { + String[] ranges = getDomainAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No zoom range for domain axis specified."); + return null; + } + + if (ranges[0] == null || ranges[1] == null) { + logger.warn("Invalid ranges for domain axis specified!"); + return null; + } + + try { + double lower = Double.parseDouble(ranges[0]); + double upper = Double.parseDouble(ranges[1]); + + return new DoubleBounds(lower, upper); + } + catch (NumberFormatException nfe) { + logger.warn("Invalid ranges for domain axis specified: " + nfe); + } + + return null; + } + + + public Bounds getValueAxisRange() { + String[] ranges = getValueAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No zoom range for domain axis specified."); + return null; + } + + if (ranges[0] == null || ranges[1] == null) { + logger.warn("Invalid ranges for domain axis specified!"); + return null; + } + + try { + double lower = Double.parseDouble(ranges[0]); + double upper = Double.parseDouble(ranges[1]); + + return new DoubleBounds(lower, upper); + } + catch (NumberFormatException nfe) { + logger.warn("Invalid ranges for domain axis specified: " + nfe); + } + + return null; + } + + + protected void adaptZoom(XYPlot plot) { + logger.debug("Adapt zoom of Timeseries chart."); + + zoomX(plot, plot.getDomainAxis(), getXBounds(0), getDomainAxisRange()); + + Bounds valueAxisBounds = getValueAxisRange(); + + for (int j = 0, n = plot.getRangeAxisCount(); j < n; j++) { + zoomY( + plot, + plot.getRangeAxis(j), + getYBounds(j), + valueAxisBounds); + } + } + + + /** + * @param plot the plot. + * @param axis the value (x, time) axis of which to set bounds. + * @param total the current bounds (?). + */ + protected void zoomX( + XYPlot plot, + ValueAxis axis, + Bounds total,//we could equally nicely getXBounds(0) + Bounds user + ) { + if (logger.isDebugEnabled()) { + logger.debug("== Zoom X axis =="); + logger.debug(" Total axis range : " + total); + logger.debug(" User defined range: " + user); + } + + if (user != null) { + long min = total.getLower().longValue(); + long max = total.getUpper().longValue(); + long diff = max > min ? max - min : min - max; + + long newMin = Math.round(min + user.getLower().doubleValue() * diff); + long newMax = Math.round(min + user.getUpper().doubleValue() * diff); + + TimeBounds newBounds = new TimeBounds(newMin, newMax); + + logger.debug(" Zoom axis to: " + newBounds); + + newBounds.applyBounds(axis, AXIS_SPACE); + } + else { + logger.debug("No user specified zoom values found!"); + if (total != null && axis != null) { + total.applyBounds(axis, AXIS_SPACE); + } + } + } + + + /** + * @param user zoom values in percent. + */ + protected void zoomY( + XYPlot plot, + ValueAxis axis, + Bounds total, + Bounds user + ) { + if (logger.isDebugEnabled()) { + logger.debug("== Zoom Y axis =="); + logger.debug(" Total axis range : " + total); + logger.debug(" User defined range: " + user); + } + + if (user != null) { + double min = total.getLower().doubleValue(); + double max = total.getUpper().doubleValue(); + double diff = max > min ? max - min : min - max; + + double newMin = min + user.getLower().doubleValue() * diff; + double newMax = min + user.getUpper().doubleValue() * diff; + + DoubleBounds newBounds = new DoubleBounds(newMin, newMax); + + logger.debug(" Zoom axis to: " + newBounds); + + newBounds.applyBounds(axis, AXIS_SPACE); + } + else { + logger.debug("No user specified zoom values found!"); + if (total != null && axis != null) { + total.applyBounds(axis, AXIS_SPACE); + } + } + } + + + /** + * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the + * X axis. + * + * (Duplicate in XYChartGenerator). + * + * @param plot The XYPlot of the chart. + */ + protected void adjustAxes(XYPlot plot) { + ValueAxis xaxis = plot.getDomainAxis(); + + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return; + } + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getXAxisLabelFontSize()); + + xaxis.setLabelFont(labelFont); + xaxis.setTickLabelFont(labelFont); + } + + + /** + * Do Points out. + */ + protected void doPoints( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible, + int axisIndex + ) { + String seriesName = aandf.getFacetDescription(); + TimeSeries series = new StyledTimeSeries(seriesName, theme); + + // Add text annotations for single points. + List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); + HashMap<Day, String> names = new HashMap<Day, String>(); + + try { + JSONArray points = new JSONArray((String) o); + for (int i = 0, P = points.length(); i < P; i++) { + JSONArray array = points.getJSONArray(i); + double x = array.getDouble(0); + double y = array.getDouble(1); + String name = array.getString(2); + boolean act = array.getBoolean(3); + if (!act) { + continue; + } + long l = (new Double(x)).longValue(); + Date date = new Date(l); + Day day = new Day(date); + series.add(day, y, false); + names.put(day, name); + } + } + catch(JSONException e){ + logger.error("Could not decode json."); + } + + TimeSeriesCollection tsc = new TimeSeriesCollection(); + tsc.addSeries(series); + // Add Annotations. + for (int i = 0, S = series.getItemCount(); i < S; i++) { + double x = tsc.getXValue(0, i); + double y = tsc.getYValue(0, i); + xy.add(new CollisionFreeXYTextAnnotation( + names.get(series.getTimePeriod(i)), x, y)); + } + FLYSAnnotation annotations = + new FLYSAnnotation(null, null, null, theme); + annotations.setTextAnnotations(xy); + + // Do not generate second legend entry. (null was passed for the aand before). + doAnnotations(annotations, null, theme, visible); + + addAxisDataset(tsc, axisIndex, visible); + } + + public void addDomainAxisMarker(XYPlot plot) { + logger.debug("domainmarkers: " + domainMarker.size()); + for (Marker marker: domainMarker) { + logger.debug("adding domain marker"); + plot.addDomainMarker(marker, Layer.BACKGROUND); + } + domainMarker.clear(); + } + + public void addValueAxisMarker(XYPlot plot) { + for (Marker marker: valueMarker) { + logger.debug("adding value marker.."); + plot.addRangeMarker(marker, Layer.BACKGROUND); + } + valueMarker.clear(); + } + + public void addAttribute(String seriesKey, String name) { + attributes.put(seriesKey, name); + } + + protected void applySeriesAttributes(XYPlot plot) { + int count = plot.getDatasetCount(); + for (int i = 0; i < count; i++) { + XYDataset data = plot.getDataset(i); + if (data == null) { + continue; + } + int seriesCount = data.getSeriesCount(); + for (int j = 0; j < seriesCount; j++) { + StyledTimeSeries series = + (StyledTimeSeries)getSeriesOf(data, j); + String key = series.getKey().toString(); + if (attributes.containsKey(key)) { + if (attributes.get(key).equals("interpolate")) { + XYLineAndShapeRenderer renderer = + series.getStyle().getRenderer(); + renderer.setSeriesPaint( + j, + renderer.getSeriesFillPaint(j)); + renderer.setSeriesShapesFilled(j, false); + } + } + if (attributes.containsKey(key)) { + if(attributes.get(key).equals("outline")) { + XYLineAndShapeRenderer renderer = + series.getStyle().getRenderer(); + renderer.setSeriesPaint( + j, + renderer.getSeriesFillPaint(j)); + renderer.setDrawOutlines(true); + } + } + } + } + } + + /** Two Ranges that span a rectangular area. */ + public static class Area { + protected Range xRange; + protected Range yRange; + + public Area(Range rangeX, Range rangeY) { + this.xRange = rangeX; + this.yRange = rangeY; + } + + public Area(ValueAxis axisX, ValueAxis axisY) { + this.xRange = axisX.getRange(); + this.yRange = axisY.getRange(); + } + + public double ofLeft(double percent) { + return xRange.getLowerBound() + + xRange.getLength() * percent; + } + + public double ofRight(double percent) { + return xRange.getUpperBound() + - xRange.getLength() * percent; + } + + public double ofGround(double percent) { + return yRange.getLowerBound() + + yRange.getLength() * percent; + } + + public double atTop() { + return yRange.getUpperBound(); + } + + public double atGround() { + return yRange.getLowerBound(); + } + + public double atRight() { + return xRange.getUpperBound(); + } + + public double atLeft() { + return xRange.getLowerBound(); + } + + public double above(double percent, double base) { + return base + yRange.getLength() * percent; + } + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TypeSection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,136 @@ +package de.intevation.flys.exports; + +import org.apache.log4j.Logger; + +import de.intevation.artifactdatabase.state.Attribute; +import de.intevation.artifactdatabase.state.DefaultSection; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class TypeSection extends DefaultSection { + + private static final Logger logger = Logger.getLogger(TypeSection.class); + + public TypeSection(String key) { + super(key); + } + + + /** Set a string value for a attribute with additional (choice) type. */ + public void setChoiceStringValue(String key, String value, String choiceType) { + if (value == null || value.length() == 0) { + return; + } + + Attribute attr = getAttribute(key); + if (attr == null) { + attr = new ChoiceStringAttribute(key, value, true, choiceType); + addAttribute(key, attr); + } + else { + attr.setValue(value); + } + } + + + public void setStringValue(String key, String value) { + if (value == null || value.length() == 0) { + return; + } + + Attribute attr = getAttribute(key); + if (attr == null) { + attr = new StringAttribute(key, value, true); + addAttribute(key, attr); + } + else { + attr.setValue(value); + } + } + + + public String getStringValue(String key) { + Attribute attr = getAttribute(key); + + if (attr instanceof StringAttribute) { + return (String) attr.getValue(); + } + + logger.debug("attribute " + key + " not found in typesection.getString"); + + return null; + } + + + public void setIntegerValue(String key, int value) { + Attribute attr = getAttribute(key); + if (attr == null) { + attr = new IntegerAttribute(key, value, true); + addAttribute(key, attr); + } + else { + attr.setValue(value); + } + } + + + public Integer getIntegerValue(String key) { + Attribute attr = getAttribute(key); + + if (attr instanceof IntegerAttribute) { + return (Integer) attr.getValue(); + } + + return null; + } + + + + public void setDoubleValue(String key, double value) { + Attribute attr = getAttribute(key); + if (attr == null) { + attr = new DoubleAttribute(key, value, true); + addAttribute(key, attr); + } + else { + attr.setValue(value); + } + } + + + public Double getDoubleValue(String key) { + Attribute attr = getAttribute(key); + + if (attr instanceof DoubleAttribute) { + return (Double) attr.getValue(); + } + + return null; + } + + + public void setBooleanValue(String key, boolean value) { + Attribute attr = getAttribute(key); + if (attr == null) { + attr = new BooleanAttribute(key, value, true); + addAttribute(key, attr); + } + else { + attr.setValue(value); + } + } + + + public Boolean getBooleanValue(String key) { + Attribute attr = getAttribute(key); + + if (attr instanceof BooleanAttribute) { + return (Boolean) attr.getValue(); + } + + return null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/VisibleAttribute.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,42 @@ +package de.intevation.flys.exports; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.state.DefaultAttribute; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class VisibleAttribute extends DefaultAttribute { + + protected boolean visible; + + + public VisibleAttribute(String name, Object value, boolean visible) { + super(name, value); + this.visible = visible; + } + + + /** + * This implementation of Attribute calls DefaultAttribute.toXML() first. + * After this, a new Attr <i>display</i> is added to the resulting Node. + * + * @param parent The parent Node. + * + * @return a new Node that represents this Attribute. + */ + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + + Element ele = (Element) super.toXML(parent); + ele.setAttribute("display", String.valueOf(visible)); + + return ele; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,114 @@ +package de.intevation.flys.exports; + +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.WKms; + +import org.apache.log4j.Logger; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; + + +/** + * An OutGenerator that generates w differences curves. + */ +public class WDifferencesCurveGenerator +extends LongitudinalSectionGenerator +implements FacetTypes +{ + public enum YAXIS { + W(0), + D(1), + Q(2); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + /** The logger that is used in this generator. */ + private static Logger logger = + Logger.getLogger(WDifferencesCurveGenerator.class); + + /** Key for internationalized title of WDiff charts. */ + public final static String I18N_WDIFF_TITLE = "chart.w_differences.title"; + + /** Default for internationalized title (when no translation found). */ + public final static String I18N_WDIFF_TITLE_DEFAULT = "Differences"; + + public final static String I18N_WDIFF_SUBTITLE = + "chart.w_differences.subtitle"; + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + /** + * Get internationalized title for chart. + * @return internationalized Chart title. + */ + @Override + public String getDefaultChartTitle() { + return msg(I18N_WDIFF_TITLE, I18N_WDIFF_TITLE_DEFAULT); + } + + + @Override + protected String getDefaultChartSubtitle() { + return getRiverName(); + } + + + /** + * Gets key to look up internationalized String for the charts subtitle. + * @return key to look up translated subtitle. + */ + @Override + protected String getChartSubtitleKey() { + return I18N_WDIFF_SUBTITLE; + } + + + /** + * + */ + @Override + public JFreeChart generateChart() { + JFreeChart chart = super.generateChart(); + if (chart != null && chart.getPlot() != null) { + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setRangeZeroBaselineVisible(true); + } + return chart; + } + + + /** + * Get name of series (displayed in legend). + * @return name of the series. + */ + protected String getSeriesName(WKms wqkms, String mode) { + String name = wqkms.getName(); + String prefix = (name != null && name.indexOf(mode) >= 0) + ? null + : mode; + + return (prefix != null && prefix.length() > 0) + ? prefix + "(" + name +")" + : name; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * w differences. + */ +public class WDifferencesCurveInfoGenerator +extends ChartInfoGenerator +{ + public WDifferencesCurveInfoGenerator() { + super(new WDifferencesCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,258 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Date; +import java.text.DateFormat; +import java.util.Locale; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JRException; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.flys.artifacts.WINFOArtifact; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WKmsJRDataSource; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.Formatter; + +/** + * (CSV)Exporter for WDifferences. + */ +public class WDifferencesExporter extends AbstractExporter { + + /** The logger used in this exporter. */ + private static Logger logger = Logger.getLogger(WDifferencesExporter.class); + + + public static final String WDIFF_CSV_KM_HEADER = + "export.w_differences.csv.header.km"; + + public static final String WDIFF_CSV_W_HEADER = + "export.w_differences.csv.header.w"; + + public static final String WDIFF_DEFAULT_CSV_KM_HEADER = "Fluss-Km"; + public static final String WDIFF_DEFAULT_CSV_W_HEADER = "m"; + + public static final String PDF_HEADER_MODE = "export.wdifferences.pdf.mode"; + public static final String JASPER_FILE = "export.wdifferences.pdf.file"; + + /** The storage that contains all WKms objects for the different facets. */ + protected List<WKms[]> data; + + + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("WDifferencesExporter.init"); + + super.init(request, out, context); + + this.data = new ArrayList<WKms[]>(); + } + + + /** + * Genereate data in csv format. + */ + @Override + public void generate() + throws IOException + { + logger.debug("WDifferencesExporter.generate"); + + if (facet == null) { + throw new IOException("invalid (null) facet for exporter"); + } + else if (facet.equals(AbstractExporter.FACET_CSV)) { + generateCSV(); + } + else if (facet.equals(AbstractExporter.FACET_PDF)) { + generatePDF(); + } + else { + throw new IOException("invalid facet (" + facet + ") for exporter"); + } + } + + + /** + * Adds given data. + * @param d either a WKms or a CalculationResult to add to data. + */ + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WKms []) { + data.add((WKms [])d); + } + } + else if (d instanceof WKms) { + data.add(new WKms[] { (WKms) d }); + } + } + + + /** + * Lets writer write all data (including header). + * @param writer Writer to write data with. + */ + @Override + protected void writeCSVData(CSVWriter writer) { + logger.info("WDifferencesExporter.writeData"); + + writeCSVHeader(writer); + + for (WKms[] tmp: data) { + for (WKms wkms: tmp) { + wKms2CSV(writer, wkms); + } + } + } + + + /** + * Lets csvwriter write the header (first line in file). + * @param writer Writer to write header with. + */ + protected void writeCSVHeader(CSVWriter writer) { + logger.info("WDifferencesExporter.writeCSVHeader"); + + writer.writeNext(new String[] { + msg(WDIFF_CSV_KM_HEADER, WDIFF_DEFAULT_CSV_KM_HEADER), + msg(WDIFF_CSV_W_HEADER, WDIFF_DEFAULT_CSV_W_HEADER) + }); + } + + + protected void wKms2CSV(CSVWriter writer, WKms wkms) { + logger.debug("WDifferencesExporter.wKms2CSV"); + + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + int size = wkms.size(); + + for (int i = 0; i < size; i ++) { + + writer.writeNext(new String[] { + kmf.format(wkms.getKm(i)), + wf.format(wkms.getW(i)) + }); + } + } + + + /** + * Returns the number formatter for kilometer values. + * + * @return the number formatter for kilometer values. + */ + protected NumberFormat getKmFormatter() { + return Formatter.getWaterlevelKM(context); + } + + + /** + * Returns the number formatter for W values. + * + * @return the number formatter for W values. + */ + protected NumberFormat getWFormatter() { + return Formatter.getWaterlevelW(context); + } + + + @Override + protected void writePDF(OutputStream out) { + WKmsJRDataSource source = createJRData(); + + String jasperFile = Resources.getMsg( + context.getMeta(), + JASPER_FILE, + "/jasper/wdifferences_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + } + + protected WKmsJRDataSource createJRData() { + WKmsJRDataSource source = new WKmsJRDataSource(); + + addMetaData(source); + for (WKms[] tmp: data) { + for (WKms wkms: tmp) { + addWKmsData(source, wkms); + } + } + return source; + } + + + protected void addMetaData(WKmsJRDataSource source) { + CallMeta meta = context.getMeta(); + + WINFOArtifact flys = (WINFOArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + String differences = FLYSUtils.getWDifferences(flys, context); + source.addMetaData("differences", differences); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "W Differences")); + } + + protected void addWKmsData(WKmsJRDataSource source, WKms wkms) { + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + int size = wkms.size(); + + for (int i = 0; i < size; i ++) { + + source.addData(new String[] { + kmf.format(wkms.getKm(i)), + wf.format(wkms.getW(i)) + }); + } + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WaterlevelExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,734 @@ +package de.intevation.flys.exports; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.w3c.dom.Document; + +import org.apache.log4j.Logger; + +import au.com.bytecode.opencsv.CSVWriter; + +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JRException; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.flys.model.Gauge; + +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WKmsJRDataSource; +import de.intevation.flys.artifacts.model.fixings.FixRealizingResult; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.FLYSUtils.WQ_MODE; +import de.intevation.flys.utils.Formatter; + + +/** + * Generates different output formats (wst, csv, pdf) of data that resulted from + * a waterlevel computation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WaterlevelExporter extends AbstractExporter { + + /** The logger used in this exporter.*/ + private static Logger logger = Logger.getLogger(WaterlevelExporter.class); + + public static final String FACET_WST = "wst"; + + public static final String CSV_KM_HEADER = + "export.waterlevel.csv.header.km"; + + public static final String CSV_W_HEADER = + "export.waterlevel.csv.header.w"; + + public static final String CSV_Q_HEADER = + "export.waterlevel.csv.header.q"; + + public static final String CSV_Q_DESC_HEADER = + "export.waterlevel.csv.header.q.desc"; + + public static final String CSV_W_DESC_HEADER = + "export.waterlevel.csv.header.w.desc"; + + public static final String CSV_LOCATION_HEADER = + "export.waterlevel.csv.header.location"; + + public static final String CSV_GAUGE_HEADER = + "export.waterlevel.csv.header.gauge"; + + public static final String CSV_META_RESULT = + "export.waterlevel.csv.meta.result"; + + public static final String CSV_META_CREATION = + "export.waterlevel.csv.meta.creation"; + + public static final String CSV_META_CALCULATIONBASE = + "export.waterlevel.csv.meta.calculationbase"; + + public static final String CSV_META_RIVER = + "export.waterlevel.csv.meta.river"; + + public static final String CSV_META_RANGE = + "export.waterlevel.csv.meta.range"; + + public static final String CSV_META_GAUGE = + "export.waterlevel.csv.meta.gauge"; + + public static final String CSV_META_Q = + "export.waterlevel.csv.meta.q"; + + public static final String CSV_META_W = + "export.waterlevel.csv.meta.w"; + + public static final String CSV_NOT_IN_GAUGE_RANGE = + "export.waterlevel.csv.not.in.gauge.range"; + + + public static final Pattern NUMBERS_PATTERN = + Pattern.compile("\\D*(\\d++.\\d*)\\D*"); + + public static final String DEFAULT_CSV_KM_HEADER = "Fluss-Km"; + public static final String DEFAULT_CSV_W_HEADER = "W [NN + m]"; + public static final String DEFAULT_CSV_Q_HEADER = "Q [m\u00b3/s]"; + public static final String DEFAULT_CSV_Q_DESC_HEADER = "Bezeichnung"; + public static final String DEFAULT_CSV_W_DESC_HEADER = "W/Pegel [cm]"; + public static final String DEFAULT_CSV_LOCATION_HEADER = "Lage"; + public static final String DEFAULT_CSV_GAUGE_HEADER = "Bezugspegel"; + public static final String DEFAULT_CSV_NOT_IN_GAUGE_RANGE = + "außerhalb des gewählten Bezugspegels"; + + public static final String PDF_HEADER_MODE = "export.waterlevel.pdf.mode"; + public static final String JASPER_FILE = "export.waterlevel.pdf.file"; + + /** The storage that contains all WQKms objects for the different facets.*/ + protected List<WQKms[]> data; + + + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("WaterlevelExporter.init"); + + super.init(request, out, context); + + this.data = new ArrayList<WQKms[]>(); + } + + + @Override + public void generate() + throws IOException + { + logger.debug("WaterlevelExporter.generate"); + + if (facet != null && facet.equals(AbstractExporter.FACET_CSV)) { + generateCSV(); + } + else if (facet != null && facet.equals(FACET_WST)) { + generateWST(); + } + else if (facet != null && facet.equals(AbstractExporter.FACET_PDF)) { + generatePDF(); + } + else { + throw new IOException("invalid facet for exporter"); + } + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof WQKms []) { + data.add((WQKms [])d); + } + else if (d instanceof FixRealizingResult) { + data.add(((FixRealizingResult) d).getWQKms()); + } + } + } + + + /** + * This method is used to prepare the column titles of waterlevel exports. + * Titles in this export include the Q value. If a Q value matches a named + * main value (as HQ100 or MNQ) this named main value should be used as + * title. This method resets the name of the <i>wqkms</i> object if such + * named main value fits to the chosen Q. + * + * @param winfo A WINFO Artifact. + * @param wqkms A WQKms object that should be prepared. + */ + protected String getColumnTitle(WINFOArtifact winfo, WQKms wqkms) { + logger.debug("WaterlevelExporter.prepareNamedValue"); + + String name = wqkms.getName(); + + logger.debug("Name of WQKms = '" + name + "'"); + + if (name.indexOf("W=") >= 0) { + return name; + } + + Matcher m = NUMBERS_PATTERN.matcher(name); + + if (m.matches()) { + String raw = m.group(1); + + try { + double v = Double.valueOf(raw); + + String nmv = FLYSUtils.getNamedMainValue(winfo, v); + + if (nmv != null && nmv.length() > 0) { + nmv = FLYSUtils.stripNamedMainValue(nmv); + nmv += "=" + String.valueOf(v); + logger.debug("Set named main value '" + nmv + "'"); + + return nmv; + } + } + catch (NumberFormatException nfe) { + // do nothing here + } + } + + return name; + } + + + protected String getCSVRowTitle(WINFOArtifact winfo, WQKms wqkms) { + logger.debug("WaterlevelExporter.prepareNamedValue"); + + String name = wqkms.getName(); + + logger.debug("Name of WQKms = '" + name + "'"); + + WQ_MODE wqmode = FLYSUtils.getWQMode(winfo); + + if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.QGAUGE) { + return localizeWQKms(winfo, wqkms); + } + + Double v = wqkms.getRawValue(); + + String nmv = FLYSUtils.getNamedMainValue(winfo, v); + + if (nmv != null && nmv.length() > 0) { + nmv = FLYSUtils.stripNamedMainValue(nmv); + logger.debug("Set named main value '" + nmv + "'"); + + return nmv; + } + + return localizeWQKms(winfo, wqkms); + } + + + /** + * Get a string like 'W=' or 'Q=' with a number following in localized + * format. + */ + protected String localizeWQKms(WINFOArtifact winfo, WQKms wqkms) { + WQ_MODE wqmode = FLYSUtils.getWQMode(winfo); + Double rawValue = wqkms.getRawValue(); + + if (rawValue == null) { + return wqkms.getName(); + } + + NumberFormat nf = Formatter.getRawFormatter(context); + + if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.WGAUGE) { + return "W=" + nf.format(rawValue); + } + else { + return "Q=" + nf.format(rawValue); + } + } + + + @Override + protected void writeCSVData(CSVWriter writer) { + logger.info("WaterlevelExporter.writeData"); + + WQ_MODE mode = FLYSUtils.getWQMode((FLYSArtifact)master); + boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; + boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; + FLYSUtils.WQ_INPUT input + = FLYSUtils.getWQInputMode((FLYSArtifact)master); + + writeCSVMeta(writer); + writeCSVHeader(writer, atGauge, isQ); + + for (WQKms[] tmp: data) { + for (WQKms wqkms: tmp) { + wQKms2CSV(writer, wqkms, atGauge, isQ); + } + } + } + + + protected void writeCSVMeta(CSVWriter writer) { + logger.info("WaterlevelExporter.writeCSVMeta"); + + CallMeta meta = context.getMeta(); + + FLYSArtifact flys = (FLYSArtifact) master; + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_RESULT, + CSV_META_RESULT, + new Object[] { FLYSUtils.getRivername(flys) }) + }); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_CREATION, + CSV_META_CREATION, + new Object[] { df.format(new Date()) }) + }); + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_CALCULATIONBASE, + CSV_META_CALCULATIONBASE, + new Object[] { "" }) // TODO what is required at this place? + }); + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_RIVER, + CSV_META_RIVER, + new Object[] { FLYSUtils.getRivername(flys) }) + }); + + double[] kms = FLYSUtils.getKmRange(flys); + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_RANGE, + CSV_META_RANGE, + new Object[] { kms[0], kms[kms.length-1] }) + }); + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_GAUGE, + CSV_META_GAUGE, + new Object[] { FLYSUtils.getGaugename(flys) }) + }); + + FLYSUtils.WQ_MODE wq = FLYSUtils.getWQMode(flys); + if (wq == FLYSUtils.WQ_MODE.QFREE || wq == FLYSUtils.WQ_MODE.QGAUGE) { + double[] qs = FLYSUtils.getQs(flys); + FLYSUtils.WQ_INPUT input = FLYSUtils.getWQInputMode(flys); + + String data = ""; + + if ((input == FLYSUtils.WQ_INPUT.ADAPTED || + input == FLYSUtils.WQ_INPUT.RANGE) && + qs != null && qs.length > 0) + { + data = String.valueOf(qs[0]); + data += " - " + String.valueOf(qs[qs.length-1]); + } + else if (input == FLYSUtils.WQ_INPUT.SINGLE && qs != null){ + data = String.valueOf(qs[0]); + for (int i = 1; i < qs.length; i++) { + data += ", " + String.valueOf(qs[i]); + } + } + else { + logger.warn("Could not determine Q range!"); + } + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_Q, + CSV_META_Q, + new Object[] {data}) + }); + } + else { + double[] ws = FLYSUtils.getWs(flys); + + String lower = ""; + String upper = ""; + + if (ws != null && ws.length > 0) { + lower = String.valueOf(ws[0]); + upper = String.valueOf(ws[ws.length-1]); + } + else { + logger.warn("Could not determine W range!"); + } + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + CSV_META_W, + CSV_META_W, + new Object[] { lower, upper }) + }); + } + + writer.writeNext(new String[] { "" }); + } + + + protected void writeCSVHeader( + CSVWriter writer, + boolean atGauge, + boolean isQ + ) { + logger.info("WaterlevelExporter.writeCSVHeader"); + + if (atGauge) { + writer.writeNext(new String[] { + msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), + (isQ + ? msg(CSV_Q_DESC_HEADER, DEFAULT_CSV_Q_DESC_HEADER) + : msg(CSV_W_DESC_HEADER, DEFAULT_CSV_W_DESC_HEADER)), + msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER), + msg(CSV_GAUGE_HEADER, DEFAULT_CSV_GAUGE_HEADER) + }); + } + else { + writer.writeNext(new String[] { + msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), + msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER) + }); + } + } + + + /** + * Write "rows" of csv data from wqkms with writer. + */ + protected void wQKms2CSV( + CSVWriter writer, + WQKms wqkms, + boolean atGauge, + boolean isQ + ) { + logger.debug("WaterlevelExporter.wQKms2CSV"); + + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + int size = wqkms.size(); + double[] result = new double[3]; + + FLYSArtifact flys = (FLYSArtifact) master; + Gauge gauge = FLYSUtils.getGauge(flys); + String gaugeName = gauge.getName(); + String desc = ""; + String notinrange = msg( + CSV_NOT_IN_GAUGE_RANGE, + DEFAULT_CSV_NOT_IN_GAUGE_RANGE); + + double a = gauge.getRange().getA().doubleValue(); + double b = gauge.getRange().getB().doubleValue(); + + if (flys instanceof WINFOArtifact && isQ) { + desc = getCSVRowTitle((WINFOArtifact)flys, wqkms); + } + else if (!isQ) { + Double value = FLYSUtils.getValueFromWQ(wqkms); + desc = value != null + ? Formatter.getWaterlevelW(context).format(value) : null; + } + + long startTime = System.currentTimeMillis(); + + String colDesc = desc; + if (flys instanceof WINFOArtifact) { + if (wqkms != null && wqkms.getRawValue() != null) { + WINFOArtifact winfo = (WINFOArtifact) flys; + colDesc = FLYSUtils.getNamedMainValue(winfo, wqkms.getRawValue()); + } + } + + for (int i = 0; i < size; i ++) { + result = wqkms.get(i, result); + + if (atGauge) { + writer.writeNext(new String[] { + kmf.format(result[2]), + wf.format(result[0]), + qf.format(result[1]), + colDesc, + FLYSUtils.getLocationDescription(flys, result[2]), + result[2] >= a && result[2] <= b + ? gaugeName + : notinrange + }); + } + else { + writer.writeNext(new String[] { + kmf.format(result[2]), + wf.format(result[0]), + qf.format(result[1]), + FLYSUtils.getLocationDescription(flys, result[2]) + }); + } + } + + long stopTime = System.currentTimeMillis(); + + if (logger.isDebugEnabled()) { + logger.debug("Writing CSV took " + + (float)(stopTime-startTime)/1000f + " secs."); + } + } + + + /** + * Generates the output in WST format. + */ + protected void generateWST() + throws IOException + { + logger.info("WaterlevelExporter.generateWST"); + + int cols = data.get(0).length; + WstWriter writer = new WstWriter(cols); + + writeWSTData(writer); + + writer.write(out); + } + + + protected void writeWSTData(WstWriter writer) { + logger.debug("WaterlevelExporter.writeWSTData"); + + double[] result = new double[4]; + + for (WQKms[] tmp: data) { + for (WQKms wqkms: tmp) { + int size = wqkms != null ? wqkms.size() : 0; + + addWSTColumn(writer, wqkms); + + for (int i = 0; i < size; i++) { + result = wqkms.get(i, result); + + writer.add(result); + } + + if (wqkms instanceof WQCKms) { + addWSTColumn(writer, wqkms); + + for (int c = 0; c < size; c++) { + result = wqkms.get(c, result); + + writer.addCorrected(result); + } + } + } + } + } + + + /** + * This method is used to register a new column at <i>writer</i>. The name / + * title of the column depends on the Q or W value of <i>wqkms</i>. If a Q + * was selected and the Q fits to a named main value, the title is set to + * the named main value. Otherwise, the name returned by + * <i>WQKms.getName()</i> is set. + * + * @param writer The WstWriter. + * @param wqkms The new WST column. + */ + protected void addWSTColumn(WstWriter writer, WQKms wqkms) { + if (master instanceof WINFOArtifact) { + writer.addColumn(getColumnTitle((WINFOArtifact) master, wqkms)); + } + else { + writer.addColumn(wqkms.getName()); + } + } + + + /** + * + */ + @Override + protected void writePDF(OutputStream out) { + logger.debug("write PDF"); + WKmsJRDataSource source = createJRData(); + + String jasperFile = Resources.getMsg( + context.getMeta(), + JASPER_FILE, + "/jasper/waterlevel_en.jasper"); + String confPath = Config.getConfigDirectory().toString(); + + + Map parameters = new HashMap(); + parameters.put("ReportTitle", "Exported Data"); + try { + JasperPrint print = JasperFillManager.fillReport( + confPath + jasperFile, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, out); + } + catch(JRException je) { + logger.warn("Error generating PDF Report!"); + je.printStackTrace(); + } + } + + protected WKmsJRDataSource createJRData() { + WKmsJRDataSource source = new WKmsJRDataSource(); + + WQ_MODE mode = FLYSUtils.getWQMode((FLYSArtifact)master); + boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; + boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; + + addMetaData(source); + for (WQKms[] tmp: data) { + for (WQKms wqkms: tmp) { + addWKmsData(wqkms, atGauge, isQ, source); + } + } + return source; + } + + protected void addMetaData(WKmsJRDataSource source) { + CallMeta meta = context.getMeta(); + + FLYSArtifact flys = (FLYSArtifact) master; + + source.addMetaData ("river", FLYSUtils.getRivername(flys)); + + Locale locale = Resources.getLocale(meta); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + + source.addMetaData("date", df.format(new Date())); + + double[] kms = FLYSUtils.getKmRange(flys); + source.addMetaData("range", kms[0] + " - " + kms[kms.length-1]); + + source.addMetaData("gauge", FLYSUtils.getGaugename(flys)); + + source.addMetaData("calculation", Resources.getMsg( + locale, + PDF_HEADER_MODE, + "Waterlevel")); + } + + protected void addWKmsData( + WQKms wqkms, + boolean atGauge, + boolean isQ, + WKmsJRDataSource source) + { + logger.debug("WaterlevelExporter.addWKmsData"); + + NumberFormat kmf = getKmFormatter(); + NumberFormat wf = getWFormatter(); + NumberFormat qf = getQFormatter(); + + int size = wqkms.size(); + double[] result = new double[3]; + + FLYSArtifact flys = (FLYSArtifact) master; + Gauge gauge = FLYSUtils.getGauge(flys); + String gaugeName = gauge.getName(); + String desc = ""; + String notinrange = msg( + CSV_NOT_IN_GAUGE_RANGE, + DEFAULT_CSV_NOT_IN_GAUGE_RANGE); + + double a = gauge.getRange().getA().doubleValue(); + double b = gauge.getRange().getB().doubleValue(); + + if (flys instanceof WINFOArtifact && isQ) { + desc = getCSVRowTitle((WINFOArtifact)flys, wqkms); + } + else if (!isQ) { + Double value = FLYSUtils.getValueFromWQ(wqkms); + desc = value != null + ? Formatter.getWaterlevelW(context).format(value) : null; + } + + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < size; i ++) { + result = wqkms.get(i, result); + + if (atGauge) { + source.addData(new String[] { + kmf.format(result[2]), + wf.format(result[0]), + qf.format(result[1]), + desc, + FLYSUtils.getLocationDescription(flys, result[2]), + result[2] >= a && result[2] <= b + ? gaugeName + : notinrange + }); + } + else { + source.addData(new String[] { + kmf.format(result[2]), + wf.format(result[0]), + qf.format(result[1]), + desc, + FLYSUtils.getLocationDescription(flys, result[2]), + result[2] >= a && result[2] <= b + ? gaugeName + : notinrange + }); + } + } + + long stopTime = System.currentTimeMillis(); + + if (logger.isDebugEnabled()) { + logger.debug("Writing PDF data took " + + (float)(stopTime-startTime)/1000f + " secs."); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WstWriter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,234 @@ +package de.intevation.flys.exports; + +import java.io.BufferedWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.model.WstLine; + + +/** + * A writer that creates WSTs. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WstWriter { + + /** The logger used in this class. */ + private static Logger logger = Logger.getLogger(WstWriter.class); + + /** The default unit that is written into the header of the WST. */ + public static final String DEFAULT_UNIT = "Wassserstand [NN + m]"; + + /** The lines that need to be included for the export. */ + protected Map<Double, WstLine> lines; + + /** The column names. */ + protected List<String> columnNames; + + /** The locale used to format the values. */ + protected Locale locale; + + /** The number of discharge columns. */ + protected int cols; + + /** The last Q values. */ + protected double[] qs; + + + + /** + * This constructor creates a new WstWriter with a number of Q columns. + * + * @param cols The number of columns of the resulting WST. + */ + public WstWriter(int cols) { + this.columnNames = new ArrayList<String>(cols); + this.lines = new HashMap<Double, WstLine>(); + this.qs = new double[cols]; + this.locale = Locale.US; + } + + + /** + * This method is used to create the WST from the data that has been + * inserted using add(double[]) before. + * @param out Where to write to. + */ + public void write(OutputStream out) { + logger.info("WstWriter.write"); + + PrintWriter writer = new PrintWriter( + new BufferedWriter( + new OutputStreamWriter(out))); + + this.qs = new double[cols]; + + writeHeader(writer); + + Collection<WstLine> collection = new TreeMap(lines).values(); + + for (WstLine line: collection) { + writeWLine(writer, line); + } + + writer.flush(); + writer.close(); + } + + + /** + * This method is used to add a new line to the WST. + * + * @param wqkms A 3dim double array with [W,Q, KM]. + */ + public void add(double[] wqkms) { + Double km = wqkms[2]; + + WstLine line = lines.get(km); + + if (line == null) { + line = new WstLine(km.doubleValue()); + lines.put(km, line); + } + + line.add(wqkms[0], wqkms[1]); + } + + + public void addCorrected(double[] wqckms) { + Double km = wqckms[2]; + + WstLine line = lines.get(km); + + if (line == null) { + line = new WstLine(km.doubleValue()); + lines.put(km, line); + } + + line.add(wqckms[3], wqckms[1]); + } + + + /** + * Adds a further column name. + * + * @param name The name of the new column. + */ + public void addColumn(String name) { + if (name != null) { + cols++; + + String basename = name; + + int i = 0; + while (columnNames.contains(name)) { + name = basename + "_" + i++; + + if (name.length() > 9) { + name = name.substring(name.length() - 9); + } + } + + columnNames.add(name); + } + } + + + /** + * This method writes the header of the WST. + * + * @param writer The PrintWriter that creates the output. + */ + protected void writeHeader(PrintWriter writer) { + logger.debug("WstWriter.writeHeader"); + + writer.println(cols); + writer.print(" "); + + for (String columnName: columnNames) { + writer.printf(locale, "%9s", columnName); + } + + writer.println(); + + writer.write("* KM "); + writer.write(DEFAULT_UNIT); + writer.println(); + } + + + /** + * This method writes a line with W values and a certain kilometer. + * + * @param writer The PrintWriter that is used to create the output. + * @param line The WstLine that should be written to the output. + */ + protected void writeWLine(PrintWriter writer, WstLine line) { + double km = line.getKm(); + double[] qs = line.getQs(); + int num = line.getSize(); + + if (dischargesChanged(qs)) { + writeQLine(writer, qs); + } + + writer.printf(locale, "%8.3f", km); + + for (int i = 0; i < num; i++) { + writer.printf(locale, "%9.2f", line.getW(i)); + } + + writer.println(); + } + + + /** + * Writes a discharge line (Q values) into a WST. + * + * @param qs the Q values for the next range. + */ + protected void writeQLine(PrintWriter writer, double[] qs) { + writer.write("*\u001f "); + + for (int i = 0; i < qs.length; i++) { + this.qs[i] = qs[i]; + + writer.printf(locale, "%9.2f", qs[i]); + } + + writer.println(); + } + + + /** + * This method determines if a Q has changed from the last line to the + * current one. + * + * @param newQs The Q values of the next line. + * + * @return true, if a Q value have changed, otherwise false. + */ + protected boolean dischargesChanged(double[] newQs) { + // XXX maybe there is a way to do this faster + for (int i = 0; i < cols; i++) { + if (Math.abs(newQs[i] - qs[i]) >= 0.001) { + return true; + } + } + + return false; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1025 @@ +package de.intevation.flys.exports; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; + +import de.intevation.flys.jfree.Bounds; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.jfree.DoubleBounds; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledAreaSeriesCollection; +import de.intevation.flys.jfree.StyledXYSeries; + +import java.awt.Color; +import java.awt.Font; +import javax.swing.ImageIcon; + +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; + +import org.jfree.chart.annotations.XYAnnotation; +import org.jfree.chart.annotations.XYImageAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; + +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; + +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.data.Range; + +import org.jfree.data.general.Series; + +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import org.json.JSONArray; +import org.json.JSONException; + +import org.w3c.dom.Document; + + +/** + * An abstract base class for creating XY charts. + * + * With respect to datasets, ranges and axis, there are following requirements: + * <ul> + * <li> First in, first drawn: "Early" datasets should be of lower Z-Oder + * than later ones (only works per-axis). </li> + * <li> Visible axis should initially show the range of all datasets that + * show data for this axis (even invisible ones). Motivation: Once + * a dataset (theme) has been activated, it should be on screen. </li> + * <li> There should always be a Y-Axis on the "left". </li> + * </ul> + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public abstract class XYChartGenerator extends ChartGenerator { + + public class XYAxisDataset implements AxisDataset { + /** Symbolic integer, but also coding the priority (0 goes first). */ + protected int axisSymbol; + /** List of assigned datasets (in order). */ + protected List<XYDataset> datasets; + /** Range to use to include all given datasets. */ + protected Range range; + /** Index of axis in plot. */ + protected int plotAxisIndex; + + /** Create AxisDataset. */ + public XYAxisDataset(int symb) { + this.axisSymbol = symb; + datasets = new ArrayList<XYDataset>(); + } + + /** Merge (or create given range with range so far (if any). */ + private void mergeRanges(Range subRange) { + // Avoid merging NaNs, as they take min/max place forever. + if (subRange == null || + Double.isNaN(subRange.getLowerBound()) || + Double.isNaN(subRange.getUpperBound())) { + return; + } + if (range == null) { + range = subRange; + return; + } + range = Range.combine(range, subRange); + } + + + /** Add a dataset to internal list for this axis. */ + @Override + public void addDataset(XYDataset dataset) { + datasets.add(dataset); + includeYRange(((XYSeriesCollection) dataset).getSeries(0)); + } + + /** Add a dataset, include its range. */ + public void addDataset(XYSeries series) { + addDataset(new XYSeriesCollection(series)); + } + + + /** Set Range for this axis. */ + @Override + public void setRange(Range range) { + this.range = range; + } + + + /** Get Range for this axis. */ + @Override + public Range getRange() { + return range; + } + + + /** Get Array of Datasets. */ + @Override + public XYDataset[] getDatasets() { + return (XYDataset[]) + datasets.toArray(new XYDataset[datasets.size()]); + } + + + /** Add a Dataset that describes an area. */ + public void addArea(StyledAreaSeriesCollection series) { + this.datasets.add(series); + } + + // TODO obsolete? + /** True if to be rendered as area. */ + @Override + public boolean isArea(XYDataset series) { + return (series instanceof StyledAreaSeriesCollection); + } + + /** Adjust range to include given dataset. */ + public void includeYRange(XYSeries dataset) { + mergeRanges(new Range(dataset.getMinY(), dataset.getMaxY())); + } + + /** True if no datasets given. */ + @Override + public boolean isEmpty() { + return this.datasets.isEmpty(); + } + + /** Set the 'real' axis index that this axis is mapped to. */ + @Override + public void setPlotAxisIndex(int axisIndex) { + this.plotAxisIndex = axisIndex; + } + + /** Get the 'real' axis index that this axis is mapped to. */ + @Override + public int getPlotAxisIndex() { + return this.plotAxisIndex; + } + } // class AxisDataset + + /** Enumerator over existing axes. */ + protected abstract YAxisWalker getYAxisWalker(); + + public static final int AXIS_SPACE = 5; + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(XYChartGenerator.class); + + protected List<Marker> domainMarkers = new ArrayList<Marker>(); + + protected List<Marker> valueMarkers = new ArrayList<Marker>(); + + /** The max X range to include all X values of all series for each axis. */ + protected Map<Integer, Bounds> xBounds; + + /** The max Y range to include all Y values of all series for each axis. */ + protected Map<Integer, Bounds> yBounds; + + public XYChartGenerator() { + super(); + + xBounds = new HashMap<Integer, Bounds>(); + yBounds = new HashMap<Integer, Bounds>(); + } + + + /** + * Generate the chart anew (including localized axis and all). + */ + public JFreeChart generateChart() { + logger.debug("XYChartGenerator.generateChart"); + + JFreeChart chart = ChartFactory.createXYLineChart( + getChartTitle(), + getXAxisLabel(), + getYAxisLabel(0), + null, + PlotOrientation.VERTICAL, + isLegendVisible(), + false, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setDomainAxis(createXAxis(getXAxisLabel())); + + chart.setBackgroundPaint(Color.WHITE); + plot.setBackgroundPaint(Color.WHITE); + addSubtitles(chart); + adjustPlot(plot); + + //debugAxis(plot); + + addDatasets(plot); + + //debugDatasets(plot); + + addMarkers(plot); + + recoverEmptyPlot(plot); + preparePointRanges(plot); + + //debugAxis(plot); + + localizeAxes(plot); + adjustAxes(plot); + autoZoom(plot); + + //debugAxis(plot); + + // These have to go after the autozoom. + addAnnotationsToRenderer(plot); + + // Add a logo (maybe). + addLogo(plot); + + aggregateLegendEntries(plot); + + return chart; + } + + + /** + * Return left most data points x value (on first axis). + * Shortcut, especially to be overridden in (LS) charts where + * axis could be inverted. + */ + protected double getLeftX() { + return (Double)getXBounds(0).getLower(); + } + + + /** + * Return right most data points x value (on first axis). + * Shortcut, especially to be overridden in (LS) charts where + * axis could be inverted. + */ + protected double getRightX() { + return (Double)getXBounds(0).getUpper(); + } + + + /** Add a logo as background annotation to plot. */ + protected void addLogo(XYPlot plot) { + String logo = showLogo(); + if (logo == null) { + logger.debug("No logo to show chosen"); + return; + } + + ImageIcon imageIcon = null; + if (logo.equals("none")) { + return; + } + /* + If you want to add images, remember to change code in these places: + flys-artifacts: + XYChartGenerator.java + Timeseries*Generator.java and + in the flys-client projects Chart*Propert*Editor.java. + Also, these images have to be put in + flys-artifacts/src/main/resources/images/ + flys-client/src/main/webapp/images/ + */ + java.net.URL imageURL; + if (logo.equals("Intevation")) { + imageURL = XYChartGenerator.class.getResource("/images/intevation.png"); + } + else { // TODO else if ... + imageURL = XYChartGenerator.class.getResource("/images/bfg_logo.gif"); + } + imageIcon = new ImageIcon(imageURL); + + + double xPos = 0d, yPos = 0d; + + String placeh = logoHPlace(); + String placev = logoVPlace(); + + if (placev == null || placev.equals("none")) { + placev = "top"; + } + if (placev.equals("top")) { + yPos = (Double)getYBounds(0).getUpper(); + } + else if (placev.equals("bottom")) { + yPos = (Double)getYBounds(0).getLower(); + } + else if (placev.equals("center")) { + yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-v value: " + placev); + } + + if (placeh == null || placeh.equals("none")) { + placeh = "center"; + } + if (placeh.equals("left")) { + xPos = getLeftX(); + } + else if (placeh.equals("right")) { + xPos = getRightX(); + } + else if (placeh.equals("center")) { + xPos = ((Double)getXBounds(0).getUpper() + (Double)getXBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-h value: " + placeh); + } + + logger.debug("logo position: " + xPos + "/" + yPos); + + org.jfree.ui.RectangleAnchor anchor + = org.jfree.ui.RectangleAnchor.TOP; + if (placev.equals("top")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.TOP; + } + } + else if (placev.equals("bottom")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM; + } + } + else if (placev.equals("center")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.CENTER; + } + } + + XYAnnotation xyannotation = + new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor); + plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND); + } + + + protected NumberAxis createXAxis(String label) { + return new NumberAxis(label); + } + + + @Override + protected Series getSeriesOf(XYDataset dataset, int idx) { + return ((XYSeriesCollection) dataset).getSeries(idx); + } + + + @Override + protected AxisDataset createAxisDataset(int idx) { + logger.debug("Create new XYAxisDataset for index: " + idx); + return new XYAxisDataset(idx); + } + + + /** + * Put debug output about datasets. + */ + public void debugDatasets(XYPlot plot) { + logger.debug("Number of datasets: " + plot.getDatasetCount()); + for (int i = 0, P = plot.getDatasetCount(); i < P; i++) { + if (plot.getDataset(i) == null) { + logger.debug("Dataset #" + i + " is null"); + continue; + } + logger.debug("Dataset #" + i + ":" + plot.getDataset(i)); + XYSeriesCollection series = (XYSeriesCollection) plot.getDataset(i); + logger.debug("X-Extend of Dataset: " + series.getSeries(0).getMinX() + + " " + series.getSeries(0).getMaxX()); + logger.debug("Y-Extend of Dataset: " + series.getSeries(0).getMinY() + + " " + series.getSeries(0).getMaxY()); + } + } + + + /** + * Put debug output about axes. + */ + public void debugAxis(XYPlot plot) { + logger.debug("..............."); + for (int i = 0, P = plot.getRangeAxisCount(); i < P; i++) { + if (plot.getRangeAxis(i) == null) + logger.debug("Range-Axis #" + i + " == null"); + else { + logger.debug("Range-Axis " + i + " != null [" + + plot.getRangeAxis(i).getRange().getLowerBound() + + " " + plot.getRangeAxis(i).getRange().getUpperBound() + + "]"); + } + } + for (int i = 0, P = plot.getDomainAxisCount(); i < P; i++) { + if (plot.getDomainAxis(i) == null) + logger.debug("Domain-Axis #" + i + " == null"); + else { + logger.debug("Domain-Axis " + i + " != null [" + + plot.getDomainAxis(i).getRange().getLowerBound() + + " " + plot.getDomainAxis(i).getRange().getUpperBound() + + "]"); + } + } + logger.debug("..............."); + } + + + /** + * Registers an area to be drawn. + * @param area Area to be drawn. + * @param index 'axis index' + * @param visible Whether or not to be visible (important for range calculations). + */ + public void addAreaSeries(StyledAreaSeriesCollection area, int index, boolean visible) { + if (area == null) { + logger.warn("Cannot yet render above/under curve."); + return; + } + + XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); + + if (visible) { + axisDataset.addArea(area); + } + else { + // TODO only range merging. + } + //TODO range merging. + } + + + /** + * Add given series if visible, if not visible adjust ranges (such that + * all points in data would be plotted once visible). + * @param series the dataseries to include in plot. + * @param index ('symbolic') index of the series and of its axis. + * @param visible whether or not the data should be plotted. + */ + public void addAxisSeries(XYSeries series, int index, boolean visible) { + if (series == null) { + return; + } + + logger.debug("Y Range of XYSeries: " + + series.getMinY() + " | " + series.getMaxY()); + + addAxisDataset(new XYSeriesCollection(series), index, visible); + + XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); + + if (!visible) { + // Do this also when not visible to have axis scaled by default such + // that every data-point could be seen (except for annotations). + axisDataset.includeYRange(series); + } + } + + + /** + * Add the given vertical marker to the chart. + */ + public void addDomainMarker(Marker marker) { + if (marker == null) { + return; + } + + domainMarkers.add(marker); + } + + + /** + * Add the given vertical marker to the chart. + */ + public void addValueMarker(Marker marker) { + if (marker == null) { + return; + } + + valueMarkers.add(marker); + } + + + protected void addMarkers(XYPlot plot) { + for(Marker marker : domainMarkers) { + plot.addDomainMarker(marker); + } + for(Marker marker : valueMarkers) { + plot.addRangeMarker(marker); + } + } + + + /** + * Effect: extend range of x axis to include given limits. + * + * @param bounds the given ("minimal") bounds. + * @param index index of axis to be merged. + */ + @Override + protected void combineXBounds(Bounds bounds, int index) { + if (!(bounds instanceof DoubleBounds)) { + logger.warn("Unsupported Bounds type: " + bounds.getClass()); + return; + } + + DoubleBounds dBounds = (DoubleBounds) bounds; + + if (dBounds == null + || Double.isNaN((Double) dBounds.getLower()) + || Double.isNaN((Double) dBounds.getUpper())) { + return; + } + + Bounds old = getXBounds(index); + + if (old != null) { + dBounds = (DoubleBounds) dBounds.combine(old); + } + + setXBounds(index, dBounds); + } + + + @Override + protected void combineYBounds(Bounds bounds, int index) { + if (!(bounds instanceof DoubleBounds)) { + logger.warn("Unsupported Bounds type: " + bounds.getClass()); + return; + } + + DoubleBounds dBounds = (DoubleBounds) bounds; + + if (dBounds == null + || Double.isNaN((Double) dBounds.getLower()) + || Double.isNaN((Double) dBounds.getUpper())) { + return; + } + + Bounds old = getYBounds(index); + + if (old != null) { + dBounds = (DoubleBounds) dBounds.combine(old); + } + + setYBounds(index, dBounds); + } + + + /** + * If no data is visible, draw at least empty axis. + */ + private void recoverEmptyPlot(XYPlot plot) { + if (plot.getRangeAxis() == null) { + logger.debug("debug: No range axis"); + plot.setRangeAxis(createYAxis(0)); + } + } + + + /** + * Expands X axes if only a point is shown. + */ + private void preparePointRanges(XYPlot plot) { + for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) { + + Integer key = Integer.valueOf(i); + Bounds b = getXBounds(key); + + + if (b != null && b.getLower().equals(b.getUpper())) { + logger.debug("Check whether to expand a x axis.i ("+b.getLower() + "-" + b.getUpper()+")"); + setXBounds(key, ChartHelper.expandBounds(b, 5)); + } + } + } + + + /** + * This method zooms the plot to the specified ranges in the attribute + * document or to the ranges specified by the min/max values in the + * datasets. <b>Note:</b> We determine the range manually if no zoom ranges + * are given, because JFreeCharts auto-zoom adds a margin to the left and + * right of the data area. + * + * @param plot The XYPlot. + */ + protected void autoZoom(XYPlot plot) { + logger.debug("Zoom to specified ranges."); + + Range xrange = getDomainAxisRange(); + Range yrange = getValueAxisRange(); + + ValueAxis xAxis = plot.getDomainAxis(); + + Range fixedXRange = getRangeForAxisFromSettings("X"); + if (fixedXRange != null) { + xAxis.setRange(fixedXRange); + } + else { + zoomX(plot, xAxis, getXBounds(0), xrange); + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis yaxis = plot.getRangeAxis(i); + + if (yaxis instanceof IdentifiableNumberAxis) { + IdentifiableNumberAxis idAxis = (IdentifiableNumberAxis) yaxis; + + Range fixedRange = getRangeForAxisFromSettings(idAxis.getId()); + if (fixedRange != null) { + yaxis.setRange(fixedRange); + continue; + } + } + + if (yaxis == null) { + logger.debug("Zoom problem: no Y Axis for index: " + i); + continue; + } + + logger.debug("Prepare zoom settings for y axis at index: " + i); + zoomY(plot, yaxis, getYBounds(Integer.valueOf(i)), yrange); + } + } + + + protected Range getDomainAxisRange() { + String[] ranges = getDomainAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No zoom range for domain axis specified."); + return null; + } + + if (ranges[0].length() > 0 && ranges[1].length() > 0) { + try { + double from = Double.parseDouble(ranges[0]); + double to = Double.parseDouble(ranges[1]); + + if (from == 0 && to == 0) { + logger.debug("No range specified. Lower and upper X == 0"); + return null; + } + + if (from > to) { + double tmp = to; + to = from; + from = tmp; + } + + return new Range(from, to); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for domain axis range."); + } + } + + return null; + } + + + protected Range getValueAxisRange() { + String[] ranges = getValueAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No range specified. Lower and upper Y == 0"); + return null; + } + + if (ranges[0].length() > 0 && ranges[1].length() > 0) { + try { + double from = Double.parseDouble(ranges[0]); + double to = Double.parseDouble(ranges[1]); + + if (from == 0 && to == 0) { + logger.debug("No range specified. Lower and upper Y == 0"); + return null; + } + + return from > to + ? new Range(to, from) + : new Range(from, to); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for value axis range."); + } + } + + return null; + } + + + protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + return zoom(plot, axis, bounds, x); + } + + + protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + return zoom(plot, axis, bounds, x); + } + + + /** + * Zooms the x axis to the range specified in the attribute document. + * + * @param plot The XYPlot. + * @param axis The axis the shoud be modified. + * @param bounds The whole range specified by a dataset. + * @param x A user defined range (null permitted). + * + * @return true, if a zoom range was specified, otherwise false. + */ + protected boolean zoom(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + + if (bounds == null) { + return false; + } + + if (x != null) { + double min = bounds.getLower().doubleValue(); + double max = bounds.getUpper().doubleValue(); + + if (logger.isDebugEnabled()) { + logger.debug("Minimum is: " + min); + logger.debug("Maximum is: " + max); + logger.debug("Lower zoom is: " + x.getLowerBound()); + logger.debug("Upper zoom is: " + x.getUpperBound()); + } + + double diff = max > min ? max - min : min - max; + + DoubleBounds computed = new DoubleBounds( + min + x.getLowerBound() * diff, + min + x.getUpperBound() * diff); + + computed.applyBounds(axis, AXIS_SPACE); + + logger.debug("Zoom axis to: " + computed); + + return true; + } + + bounds.applyBounds(axis, AXIS_SPACE); + return false; + } + + + /** + * Extract the minimum and maximum values for x and y axes + * which are stored in <i>xRanges</i> and <i>yRanges</i>. + * + * @param index The index of the y-Axis. + * + * @return a Range[] as follows: [x-Range, y-Range]. + */ + @Override + public Range[] getRangesForAxis(int index) { + logger.debug("getRangesForAxis " + index); + + Bounds rx = getXBounds(Integer.valueOf(0)); + Bounds ry = getYBounds(Integer.valueOf(index)); + + if (rx == null) { + logger.warn("Range for x axis not set." + + " Using default values: 0 - 1."); + rx = new DoubleBounds(0, 1); + } + if (ry == null) { + logger.warn("Range for y" + index + + " axis not set. Using default values: 0 - 1."); + ry = new DoubleBounds(0, 1); + } + + return new Range[] { + new Range(rx.getLower().doubleValue(), rx.getUpper().doubleValue()), + new Range(ry.getLower().doubleValue(), ry.getUpper().doubleValue()) + }; + } + + + /** Get X (usually horizontal) extent for given axis. */ + @Override + public Bounds getXBounds(int axis) { + return xBounds.get(axis); + } + + + /** Set X (usually horizontal) extent for given axis. */ + @Override + protected void setXBounds(int axis, Bounds bounds) { + if (bounds.getLower() == bounds.getUpper()) { + xBounds.put(axis, ChartHelper.expandBounds(bounds, 5d)); + } + else { + xBounds.put(axis, bounds); + } + } + + + /** Get Y (usually vertical) extent for given axis. */ + @Override + public Bounds getYBounds(int axis) { + return yBounds.get(axis); + } + + + /** Set Y (usually vertical) extent for given axis. */ + @Override + protected void setYBounds(int axis, Bounds bounds) { + yBounds.put(axis, bounds); + } + + + /** + * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the + * X axis. + * + * (Duplicate in TimeseriesChartGenerator) + * + * @param plot The XYPlot of the chart. + */ + protected void adjustAxes(XYPlot plot) { + ValueAxis xaxis = plot.getDomainAxis(); + + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return; + } + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getXAxisLabelFontSize()); + + xaxis.setLabelFont(labelFont); + xaxis.setTickLabelFont(labelFont); + } + + + /** + * This method walks over all axes (domain and range) of <i>plot</i> and + * calls localizeDomainAxis() for domain axes or localizeRangeAxis() for + * range axes. + * + * @param plot The XYPlot. + */ + private void localizeAxes(XYPlot plot) { + for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) { + ValueAxis axis = plot.getDomainAxis(i); + + if (axis != null) { + localizeDomainAxis(axis); + } + else { + logger.warn("Domain axis at " + i + " is null."); + } + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis axis = plot.getRangeAxis(i); + + if (axis != null) { + localizeRangeAxis(axis); + } + else { + logger.warn("Range axis at " + i + " is null."); + } + } + } + + + /** + * Overrides the NumberFormat with the NumberFormat for the current locale + * that is provided by getLocale(). + * + * @param domainAxis The domain axis that needs localization. + */ + protected void localizeDomainAxis(ValueAxis domainAxis) { + NumberFormat nf = NumberFormat.getInstance(getLocale()); + ((NumberAxis) domainAxis).setNumberFormatOverride(nf); + } + + + /** + * Overrides the NumberFormat with the NumberFormat for the current locale + * that is provided by getLocale(). + * + * @param rangeAxis The domain axis that needs localization. + */ + protected void localizeRangeAxis(ValueAxis rangeAxis) { + NumberFormat nf = NumberFormat.getInstance(getLocale()); + ((NumberAxis) rangeAxis).setNumberFormatOverride(nf); + } + + + /** + * Do Points out. + */ + protected void doPoints( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible, + int axisIndex + ) { + String seriesName = aandf.getFacetDescription(); + XYSeries series = new StyledXYSeries(seriesName, theme); + + // Add text annotations for single points. + List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); + + try { + JSONArray points = new JSONArray((String) o); + for (int i = 0, P = points.length(); i < P; i++) { + JSONArray array = points.getJSONArray(i); + double x = array.getDouble(0); + double y = array.getDouble(1); + String name = array.getString(2); + boolean act = array.getBoolean(3); + if (!act) { + continue; + } + //logger.debug(" x " + x + " y " + y ); + series.add(x, y, false); + xy.add(new CollisionFreeXYTextAnnotation(name, x, y)); + } + } + catch(JSONException e){ + logger.error("Could not decode json."); + } + + FLYSAnnotation annotations = new FLYSAnnotation(null, null, null, theme); + annotations.setTextAnnotations(xy); + + // Do not generate second legend entry. (null was passed for the aand before). + doAnnotations(annotations, null, theme, visible); + addAxisSeries(series, axisIndex, visible); + } + + + /** + * Create a hash from a legenditem. + * This hash can then be used to merge legend items labels. + * @return hash for given legenditem to identify mergeables. + */ + public static String legendItemHash(LegendItem li) { + // TODO Do proper implementation. Ensure that only mergable sets are created. + // getFillPaint() + // getFillPaintTransformer() + // getLabel() + // getLine() + // getLinePaint() + // getLineStroke() + // getOutlinePaint() + // getOutlineStroke() + // Shape getShape() + // String getToolTipText() + // String getURLText() + // boolean isLineVisible() + // boolean isShapeFilled() + // boolean isShapeOutlineVisible() + // boolean isShapeVisible() + String hash = li.getLinePaint().toString(); + String label = li.getLabel(); + if (label.startsWith("W (") || label.startsWith("W(")) { + hash += "-W-"; + } + else if (label.startsWith("Q(") || label.startsWith("Q (")) { + hash += "-Q-"; + } + + // WQ.java holds example of using regex Matcher/Pattern. + + return hash; + } + +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,267 @@ +package de.intevation.flys.exports.fixings; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.model.fixings.AnalysisPeriod; +import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult; +import de.intevation.flys.artifacts.model.fixings.QWD; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.exports.AbstractExporter; + +import de.intevation.flys.utils.Formatter; +import de.intevation.flys.utils.KMIndex; + +import java.io.IOException; +import java.io.OutputStream; + +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +/** Exports fixation analysis deltaw(t) computation results to csv. */ +public class DeltaWtExporter +extends AbstractExporter +{ + /** Private logger. */ + private static Logger log = Logger.getLogger(DeltaWtExporter.class); + + public static final String CSV_KM_HEADER = + "export.fixings.deltawt.csv.header.km"; + + public static final String CSV_DELTA_W_HEADER = + "export.fixings.deltawt.csv.header.deltaw"; + + public static final String CSV_Q_HEADER = + "export.fixings.deltawt.csv.header.q"; + + public static final String CSV_W_HEADER = + "export.fixings.deltawt.csv.header.w"; + + public static final String CSV_TRANGE_HEADER = + "export.fixings.deltawt.csv.header.time.range"; + + public static final String CSV_T_HEADER = + "export.fixings.deltawt.csv.header.t"; + + public static final String CSV_T_FORMAT = + "export.fixings.deltawt.csv.t.format"; + + public static final String DEFAULT_CSV_KM_HEADER = "km"; + + public static final String DEFAULT_CSV_DELTA_W_HEADER = "\u0394 W [cm]"; + + public static final String DEFAULT_CSV_W_HEADER = "Wasserstand [m]"; + + public static final String DEFAULT_CSV_Q_HEADER = "Abfluss [m\u00b3/s]"; + + public static final String DEFAULT_CSV_T_HEADER = "Datum"; + + public static final String DEFAULT_CSV_TRANGE_DESC_HEADER = + "Status"; + + public static final String CSV_REFERENCE = + "export.fixings.deltawt.csv.reference"; + + public static final String CSV_ANALYSIS = + "export.fixings.deltawt.csv.analysis"; + + public static final String DEFAULT_CSV_REFERENCE = + "B"; + + public static final String DEFAULT_CSV_ANALYSIS = + "A{0,number,integer}"; + + public static final String DEFAULT_CSV_T_FORMAT = + "dd.MM.yyyy"; + + protected List<KMIndex<AnalysisPeriod []>> analysisPeriods; + + protected List<KMIndex<QWD[]>> referenceEvents; + + @Override + public void init(Document request, OutputStream out, CallContext context) { + log.debug("DeltaWtExporter.init"); + super.init(request, out, context); + analysisPeriods = new ArrayList<KMIndex<AnalysisPeriod []>>(); + referenceEvents = new ArrayList<KMIndex<QWD[]>>(); + } + + @Override + protected void addData(Object d) { + log.debug("DeltaWtExporter.addData"); + if (!(d instanceof CalculationResult)) { + log.warn("Invalid data type"); + return; + } + + Object data = ((CalculationResult)d).getData(); + if (!(data instanceof FixAnalysisResult)) { + log.warn("Invalid data stored in result."); + } + FixAnalysisResult result = (FixAnalysisResult)data; + analysisPeriods.add(result.getAnalysisPeriods()); + referenceEvents.add(result.getReferenced()); + } + + @Override + protected void writeCSVData(CSVWriter writer) throws IOException { + + boolean debug = log.isDebugEnabled(); + + writeCSVHeader(writer); + + NumberFormat kmF = getKMFormatter(); + NumberFormat dwF = getDeltaWFormatter(); + NumberFormat qF = getQFormatter(); + NumberFormat wF = getWFormatter(); + + DateFormat dF = getDateFormatter(); + + String referenceS = getReference(); + + for (KMIndex<QWD[]> reference: referenceEvents) { + + for (KMIndex.Entry<QWD[]> kmEntry: reference) { + + String kmS = kmF.format(kmEntry.getKm()); + for (QWD qwd: kmEntry.getValue()) { + String deltaWS = dwF.format(qwd.getDeltaW()); + String qS = qF.format(qwd.getQ()); + String wS = wF.format(qwd.getW()); + String dateS = dF.format(qwd.getDate()); + + writer.writeNext(new String[] { + kmS, + dateS, + qS, + wS, + referenceS, + deltaWS + }); + } + } + } + + if (debug) { + log.debug("AnalysisPeriods: " + analysisPeriods.size()); + } + + String analysisTemplate = getAnalysisTemplate(); + + int analysisCount = 1; + + for (KMIndex<AnalysisPeriod []> periods: analysisPeriods) { + + // Typically resulting in A1,A2... + String analyisS = MessageFormat.format( + analysisTemplate, analysisCount); + + for (KMIndex.Entry<AnalysisPeriod []> kmEntry: periods) { + + String kmS = kmF.format(kmEntry.getKm()); + + for (AnalysisPeriod period: kmEntry.getValue()) { + QWD [] qwds = period.getQWDs(); + /* issue825 + km; Ereignis, Abfluss, GEMESSENER Wasserstand; Status (RECHTSBÃœNDIG), del W + */ + + if (qwds != null) { + for (QWD qwd: qwds) { + String deltaWS = dwF.format(qwd.getDeltaW()); + String qS = qF.format(qwd.getQ()); + String wS = wF.format(qwd.getW()); + String dateS = dF.format(qwd.getDate()); + + writer.writeNext(new String[] { + kmS, + dateS, + qS, + wS, + analyisS, + deltaWS }); + } + } + } + ++analysisCount; + } + } + writer.flush(); + } + + /** Template to create "State" strings like A1,A2... */ + protected String getAnalysisTemplate() { + return Resources.getMsg( + context.getMeta(), + CSV_ANALYSIS, DEFAULT_CSV_ANALYSIS); + } + + protected String getReference() { + return Resources.getMsg( + context.getMeta(), + CSV_REFERENCE, DEFAULT_CSV_REFERENCE); + } + + protected NumberFormat getKMFormatter() { + return Formatter.getFixDeltaWKM(context); + } + + protected NumberFormat getDeltaWFormatter() { + return Formatter.getFixDeltaWDeltaW(context); + } + + protected NumberFormat getQFormatter() { + return Formatter.getFixDeltaWQ(context); + } + + protected NumberFormat getWFormatter() { + return Formatter.getFixDeltaWW(context); + } + + protected DateFormat getDateFormatter() { + CallMeta meta = context.getMeta(); + return Formatter.getDateFormatter( + meta, + Resources.getMsg( + meta, + CSV_T_FORMAT, + DEFAULT_CSV_T_FORMAT)); + } + + protected void writeCSVHeader(CSVWriter writer) { + log.debug("DeltaWtExporter.writeCSVHeader"); + + /* issue825 + km; Ereignis, Abfluss, GEMESSENER Wasserstand; Status (RECHTSBÃœNDIG), del W + */ + + writer.writeNext(new String[] { + msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), + msg(CSV_T_HEADER, DEFAULT_CSV_T_HEADER), + msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), + msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER), + msg(CSV_TRANGE_HEADER, DEFAULT_CSV_TRANGE_DESC_HEADER), + msg(CSV_DELTA_W_HEADER, DEFAULT_CSV_DELTA_W_HEADER) + }); + } + + @Override + protected void writePDF(OutputStream out) { + // TODO: Implement me! + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixATExport.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,101 @@ +package de.intevation.flys.exports.fixings; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.FixAccess; + +import de.intevation.flys.artifacts.math.fitting.Function; +import de.intevation.flys.artifacts.math.fitting.FunctionFactory; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult; + +import de.intevation.flys.exports.AbstractExporter; + +import de.intevation.flys.utils.FLYSUtils; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +/** Export result of fixation analysis. */ +public class FixATExport extends AbstractExporter { + + /** Private logger. */ + private static Logger logger = + Logger.getLogger(FixATExport.class); + + protected Function function; + protected Parameters parameters; + + + @Override + public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { + logger.debug("AT Export doOut()."); + Object data = bundle.getData(context); + if (data instanceof CalculationResult) { + CalculationResult cr = (CalculationResult)data; + Object resData = cr.getData(); + if (resData instanceof FixAnalysisResult) { + this.parameters = ((FixAnalysisResult)resData).getParameters(); + } + } + else { + logger.debug("No CalculationResult found for AT export."); + return; + } + FixAccess access = new FixAccess((FLYSArtifact)this.master); + String f = access.getFunction(); + if (f == null || f.length() == 0) { + logger.debug("No function found for AT export."); + return; + } + this.function = FunctionFactory.getInstance().getFunction(f); + } + + @Override + public void generate() throws IOException { + if (this.function == null || this.parameters == null) { + logger.debug("No function or paramters for AT export."); + return; + } + + Writer writer = new OutputStreamWriter(out, DEFAULT_CSV_CHARSET); + + FixATWriter atWriter = new FixATWriter(this.function, this.parameters); + NodeList nodes = request.getElementsByTagName("km"); + String km = nodes.item(0).getTextContent(); + double dkm = Double.parseDouble(km); + String river = FLYSUtils.getRivername((FLYSArtifact)master); + atWriter.write(writer, context.getMeta(), river, dkm); + writer.close(); + } + + @Override + protected void writeCSVData(CSVWriter writer) throws IOException { + // The concrete writer is used to write csv data. + } + + @Override + protected void writePDF(OutputStream out) { + // Implement me! + } + + @Override + protected void addData(Object data) { + // Nothing to do here. + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,185 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.artifacts.CallMeta; + +import de.intevation.flys.artifacts.math.fitting.Function; + +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.exports.ATWriter; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; + +import java.util.Locale; + +import org.apache.log4j.Logger; + +public class FixATWriter +{ + private static Logger log = Logger.getLogger(FixATWriter.class); + + public static final String I18N_HEADER_KEY = + "fix.export.at.header"; + + public static final String I18N_HEADER_DEFAULT = + "Exported fixings discharge curve for {0} {0}-km: {1}"; + + public static final String [] Q_MAX_COLUMN = new String [] { "max_q" }; + + private static final int MAX_ITERATIONS = 10000; + private static final double EPSILON = 1e-8; + private static final double MIN_Q = 1e-4; + + protected Function function; + protected Parameters parameters; + + public FixATWriter() { + } + + public FixATWriter(Function function, Parameters parameters) { + this.function = function; + this.parameters = parameters; + } + + public void write( + Writer writer, + CallMeta meta, + String river, + double km + ) + throws IOException { + PrintWriter out = new PrintWriter(writer); + printHeader(out, meta, river, km); + + double [] coeffs = parameters.interpolate( + "km", km, function.getParameterNames()); + + double [] qMax = parameters.interpolate( + "km", km, Q_MAX_COLUMN); + + if (coeffs == null || qMax == null) { + log.debug("No data found at km " + km + "."); + return; + } + + de.intevation.flys.artifacts.math.Function funcInst = + function.instantiate(coeffs); + + // Increase Q max about 5%. + qMax[0] += Math.abs(qMax[0])*0.05; + + double wMax = funcInst.value(qMax[0]); + + if (Double.isNaN(wMax) || wMax < 0d) { + log.debug("function '" + function.getName() + + "' eval failed at " + wMax); + return; + } + + Function inverse = function.getInverse(); + + de.intevation.flys.artifacts.math.Function invInst = + inverse.instantiate(coeffs); + + double wMin = minW(invInst, wMax, qMax[0]); + + double wMinCM = wMin * 100d; + double wMaxCM = wMax * 100d; + + int wRow = ((int)wMinCM / 10) * 10; + + if ((wMinCM - (int)wMinCM) > 0d) { + wMinCM = (int)wMinCM + 1d; + } + + double w = wMinCM / 100.0; + + int wcm = ((int)wMinCM) % 10; + + if (log.isDebugEnabled()) { + log.debug("wMinCM: " + wMinCM); + log.debug("wMaxCM: " + wMaxCM); + log.debug("wcm: " + wcm); + } + + out.printf(Locale.US, "%8d", wRow); + + if (wcm > 0) { + int rest = 10 - wcm; + while (rest-- > 0) { + out.print(ATWriter.EMPTY); + } + } + + for (;;) { + while (wcm++ < 10) { + if (w > wMax) { + break; + } + double q = invInst.value(w); + if (Double.isNaN(w)) { + out.print(ATWriter.EMPTY); + } + else { + ATWriter.printQ(out, q); + } + w += 0.01d; + } + out.println(); + if (w > wMax) { + break; + } + out.printf(Locale.US, "%8d", wRow += 10); + wcm = 0; + } + + out.flush(); + } + + protected void printHeader( + PrintWriter out, + CallMeta meta, + String river, + double km + ) { + out.println(Resources.format( + meta, + I18N_HEADER_KEY, + I18N_HEADER_DEFAULT, + river, km)); + } + + private static double minW( + de.intevation.flys.artifacts.math.Function function, + double maxW, + double maxQ + ) { + double stepWidth = 10d; + + double lastW = maxW; + double lastQ = maxQ; + + for (int i = 0; i < MAX_ITERATIONS; ++i) { + double w = lastW - stepWidth; + double q = function.value(w); + + if (Double.isNaN(q) || q > lastQ || q < MIN_Q) { + if (stepWidth < EPSILON) { + break; + } + stepWidth *= 0.5d; + continue; + } + + lastW = w; + lastQ = q; + } + + return lastW; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,59 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.exports.XYChartGenerator; + +import java.io.OutputStream; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +/** + * Base class for FixChartGenerator. + */ +public abstract class FixChartGenerator +extends XYChartGenerator +{ + /** Private logger. */ + private static Logger logger = Logger.getLogger(FixChartGenerator.class); + + public static final Double INVALID_KM = Double.valueOf(-1d); + public static final String CURRENT_KM = "currentKm"; + public static final String XPATH_CHART_CURRENTKM = + "/art:action/art:attributes/art:currentKm/@art:km"; + + @Override + public void init(Document request, OutputStream out, CallContext context) { + super.init(request, out, context); + + Double currentKm = getCurrentKmFromRequest(request); + + if (logger.isDebugEnabled()) { + logger.debug("currentKm = " + currentKm); + } + + context.putContextValue(CURRENT_KM, currentKm); + } + + public static final Double getCurrentKmFromRequest(Document request) { + + String km = XMLUtils.xpathString( + request, + XPATH_CHART_CURRENTKM, + ArtifactNamespaceContext.INSTANCE); + + if (km == null) { + return INVALID_KM; + } + + try { + return Double.valueOf(km); + } + catch (NumberFormatException nfe) { + return INVALID_KM; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,426 @@ +package de.intevation.flys.exports.fixings; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.data.time.Day; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.access.FixAnalysisAccess; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.QWDDateRange; +import de.intevation.flys.artifacts.model.fixings.QWD; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.exports.TimeseriesChartGenerator; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledDomainMarker; +import de.intevation.flys.jfree.StyledTimeSeries; +import de.intevation.flys.jfree.StyledValueMarker; +import de.intevation.flys.utils.ThemeUtil; + + +/** + * Generator for Delta W(t) charts. + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixDeltaWtGenerator +extends TimeseriesChartGenerator +implements FacetTypes +{ + /** Private logger. */ + private static Logger logger = + Logger.getLogger(FixDeltaWtGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.fix.deltawt.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.fix.deltawt.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.fix.deltawt.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.fix.deltawt.yaxis.label"; + + public static final String I18N_YAXIS_SECOND_LABEL = + "chart.fix.deltawt.yaxis.second.label"; + + + public static enum YAXIS { + dW(0); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + + private FLYSArtifact artifact = null; + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } + + + @Override + protected String getChartTitle() { + return Resources.format( + context.getMeta(), + I18N_CHART_TITLE, + "", + FixChartGenerator + .getCurrentKmFromRequest(request).doubleValue()); + } + + + @Override + protected String getDefaultChartSubtitle() { + FixAnalysisAccess access = new FixAnalysisAccess(artifact); + DateRange dateRange = access.getDateRange(); + DateRange refRange = access.getReferencePeriod(); + return Resources.format( + context.getMeta(), + I18N_CHART_SUBTITLE, + "", + access.getRiver(), + dateRange.getFrom(), + dateRange.getTo(), + refRange.getFrom(), + refRange.getTo()); + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); + } + + @Override + protected String getDefaultYAxisLabel(int pos) { + if (pos == 0) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); + } + else if (pos == 1) { + return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL); + } + else { + return "NO TITLE FOR Y AXIS: " + pos; + } + } + + + @Override + public void doOut( + ArtifactAndFacet artifactFacet, + Document theme, + boolean visible + ) { + String name = artifactFacet.getFacetName(); + logger.debug("FixDeltaWtGenerator.doOut: " + name); + logger.debug("Theme description is: " + artifactFacet.getFacetDescription()); + + this.artifact = (FLYSArtifact)artifactFacet.getArtifact(); + + if (name.contains(FIX_SECTOR_AVERAGE_DWT)) { + doSectorAverageOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(FIX_REFERENCE_EVENTS_DWT)) { + doReferenceEventsOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(FIX_ANALYSIS_EVENTS_DWT)) { + doAnalysisEventsOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(FIX_DEVIATION_DWT)) { + doDeviationOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (name.equals(FIX_ANALYSIS_PERIODS_DWT)) { + doAnalysisPeriodsOut( + (FLYSArtifact) artifactFacet.getArtifact(), + artifactFacet.getData(context), + artifactFacet.getFacetDescription(), + theme, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints (artifactFacet.getData(context), + artifactFacet, + theme, visible, YAXIS.dW.idx); + } + else { + logger.warn("doOut(): unknown facet name: " + name); + return; + } + } + + + protected void doSectorAverageOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible) + { + logger.debug("doSectorAverageOut(): description = " + desc); + + QWDDateRange qwd = (QWDDateRange) data; + TimeSeriesCollection tsc = new TimeSeriesCollection(); + TimeSeries series = new StyledTimeSeries(desc, theme); + + if (qwd == null || qwd.qwd == null || qwd.dateRange == null) { + return; + } + RegularTimePeriod rtp = new Day(qwd.qwd.getDate()); + double value = qwd.qwd.getDeltaW(); + + // Draw a line spanning the analysis time. + series.add(rtp, value); + rtp = new Day(qwd.dateRange.getFrom()); + series.addOrUpdate(rtp, value); + rtp = new Day(qwd.dateRange.getTo()); + series.addOrUpdate(rtp, value); + + tsc.addSeries(series); + + addAxisDataset(tsc, 0, visible); + + if (visible && ThemeUtil.parseShowLineLabel(theme)) { + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + "\u0394 W(t) [cm] " + (float)Math.round(qwd.qwd.getDeltaW() * 10000) / 10000, + tsc.getXValue(0, 0), + qwd.qwd.getDeltaW()); + textAnnos.add(anno); + + FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, theme); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + } + + + protected void doAnalysisEventsOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible + ) { + logger.debug("doAnalysisEventsOut: desc = " + desc); + + QWD qwd = (QWD) data; + doQWDEventsOut(qwd, desc, theme, visible); + } + + + protected void doQWDEventsOut(QWD qwd, String desc, Document theme, boolean visible) + { + TimeSeriesCollection tsc = new TimeSeriesCollection(); + + TimeSeries series = new StyledTimeSeries(desc, theme); + TimeSeries interpol = new StyledTimeSeries(desc + "interpol", theme); + + if (qwd == null) { + logger.debug("doQWDEventsOut: qwd == null"); + return; + } + + Map<Integer, int[]> annoIdxMap = new HashMap<Integer, int[]>(); + + int idxInterpol = 0; + int idxRegular = 0; + RegularTimePeriod rtp = new Day(qwd.getDate()); + double value = qwd.getDeltaW(); + boolean interpolate = qwd.getInterpolated(); + if (interpolate) { + if(interpol.addOrUpdate(rtp, value) == null) { + annoIdxMap.put( + 0, + new int[]{1, idxInterpol}); + idxInterpol++; + } + } + else { + if(series.addOrUpdate(rtp, value) == null) { + annoIdxMap.put( + 0, + new int[]{0, idxRegular}); + idxRegular++; + } + } + + tsc.addSeries(series); + tsc.addSeries(interpol); + addAxisDataset(tsc, 0, visible); + addAttribute(desc + "interpol", "interpolate"); + addAttribute(desc, "outline"); + + doQWDTextAnnotations(annoIdxMap, tsc, qwd, theme, visible); + } + + + /** + * @param annoIdxMap map of index in qwds to series/data item indices in tsc. + */ + protected void doQWDTextAnnotations(Map<Integer, int[]> annoIdxMap, + TimeSeriesCollection tsc, QWD qwd, Document theme, + boolean visible) { + logger.debug("doQWDTextAnnotation()"); + + if (!visible || !ThemeUtil.parseShowPointLabel(theme)) { + logger.debug("doQWDTextAnnotation: annotation not visible"); + return; + } + + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + Set<Map.Entry<Integer, int[]>> entries = annoIdxMap.entrySet(); + + for(Map.Entry<Integer, int[]> entry : entries) { + int[] idxs = entry.getValue(); + double x = tsc.getXValue(idxs[0], idxs[1]); + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + qwd.getQ() + " m\u00B3/s", + x, + qwd.getDeltaW()); + textAnnos.add(anno); + } + + FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, theme); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + + + protected void doReferenceEventsOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible + ) { + logger.debug("doReferenceEventsOut: desc = " + desc); + + QWD qwd = (QWD) data; + doQWDEventsOut(qwd, desc, theme, visible); + } + + + protected void doDeviationOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible + ) { + logger.debug("doDeviationOut: desc = " + desc); + + if (data == null || !visible) { + logger.debug("no standard deviation"); + return; + } + double[] value = (double[]) data; + StyledDomainMarker lower = new StyledDomainMarker((value[0] * -1), 0, theme); + StyledDomainMarker upper = new StyledDomainMarker(0, value[0], theme); + + valueMarker.add(lower); + valueMarker.add(upper); + } + + + protected void doAnalysisPeriodsOut( + FLYSArtifact artifact, + Object data, + String desc, + Document theme, + boolean visible + ) { + logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); + + DateRange[] ranges = (DateRange[]) data; + if (ranges == null || !visible) { + return; + } + for (int i = 0; i < ranges.length; i++) { + logger.debug("creating domain marker"); + RegularTimePeriod start = new Day(ranges[i].getFrom()); + RegularTimePeriod end = new Day(ranges[i].getTo()); + StyledDomainMarker marker = + new StyledDomainMarker(start.getMiddleMillisecond(), + end.getMiddleMillisecond(), theme); + marker.useSecondColor(i % 2 == 0); + domainMarker.add(marker); + } + logger.debug("domainmarkers: " + domainMarker.size()); + } + + + @Override + public void init(Document request, OutputStream out, CallContext context) { + super.init(request, out, context); + + Double currentKm = FixChartGenerator.getCurrentKmFromRequest(request); + + if (logger.isDebugEnabled()) { + logger.debug("currentKm = " + currentKm); + } + + context.putContextValue("currentKm", currentKm); + + StyledValueMarker marker = new StyledValueMarker(0, request); + valueMarker.add(marker); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,11 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.flys.exports.ChartInfoGenerator; + +public class FixDeltaWtInfoGenerator extends ChartInfoGenerator { + + public FixDeltaWtInfoGenerator() { + super(new FixDeltaWtGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,138 @@ +package de.intevation.flys.exports.fixings; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.fixings.FixDerivateFacet; +import de.intevation.flys.artifacts.model.fixings.FixFunction; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.exports.ChartGenerator; +import de.intevation.flys.jfree.JFreeUtil; +import de.intevation.flys.jfree.StyledXYSeries; + +/** + * Generator for fixation derived function curve. + * + * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a> + */ +public class FixDerivedCurveGenerator +extends FixChartGenerator +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(FixDerivedCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.fixings.derivedcurve.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.fixings.derivedcurve.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.fixings.derivedcurve.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.fixings.derivedcurve.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = + "Ableitungskurve"; + + public static final String I18N_XAXIS_LABEL_DEFAULT = + "Q [m\u00B3/s]"; + + public static final String I18N_YAXIS_LABEL_DEFAULT = + "W [NN + m]"; + + public static enum YAXIS { + W(0), + Q(1); + public int idx; + private YAXIS(int c) { + idx = c; + } + } + + + @Override + public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doOut"); + + if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) { + doPoints(aaf.getData(context), + aaf, + doc, visible, YAXIS.W.idx); + } + else { + FixDerivateFacet facet = (FixDerivateFacet)aaf.getFacet(); + FixFunction func = (FixFunction)facet.getData( + aaf.getArtifact(), context); + + if (func == null) { + logger.warn("doOut: Facet does not contain FixFunction"); + return; + } + + double maxQ = func.getMaxQ(); + + if (maxQ > 0) { + StyledXYSeries series = JFreeUtil.sampleFunction2D( + func.getFunction(), + doc, + aaf.getFacetDescription(), + 500, // number of samples + 0.0 , // start + maxQ); // end + addAxisSeries(series, 0, visible); + } + } + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + + @Override + protected String getChartTitle() { + return Resources.format( + context.getMeta(), + I18N_CHART_TITLE, + I18N_CHART_TITLE_DEFAULT, + context.getContextValue(CURRENT_KM)); + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + + @Override + protected ChartGenerator.YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } +} + +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,11 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.flys.exports.ChartInfoGenerator; + +public class FixDerivedCurveInfoGenerator extends ChartInfoGenerator { + + public FixDerivedCurveInfoGenerator() { + super(new FixDerivedCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,316 @@ +package de.intevation.flys.exports.fixings; + +import java.awt.BasicStroke; +import java.awt.Color; + +import org.apache.log4j.Logger; +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.ValueMarker; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.fixings.AnalysisPeriod; +import de.intevation.flys.artifacts.model.fixings.QWD; +import de.intevation.flys.exports.ChartGenerator; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.StyledAreaSeriesCollection; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.utils.KMIndex; + +public class FixLongitudinalSectionGenerator +extends FixChartGenerator +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(FixLongitudinalSectionGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.fixings.longitudinalsection.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.fixings.longitudinalsection.subtitle"; + + public static final String I18N_XAXIS_LABEL = + "chart.fixings.longitudinalsection.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.fixings.longitudinalsection.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = + "Fixierungsanalyse"; + + public static final String I18N_XAXIS_LABEL_DEFAULT = + "[km]"; + + public static final String I18N_YAXIS_LABEL_DEFAULT = + "delta W [cm]"; + + public static enum YAXIS { + dW(0); + public int idx; + private YAXIS(int c) { + idx = c; + } + } + + @Override + public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + String name = aaf.getFacetName(); + logger.debug("FixLongitudinalSectionGenerator: doOut: " + name); + + if (name.contains(FIX_SECTOR_AVERAGE_LS_DEVIATION)) { + doSectorAverageDeviationOut(aaf, doc, visible); + } + else if (name.contains(FIX_SECTOR_AVERAGE_LS)) { + doSectorAverageOut(aaf, doc, visible); + } + else if (name.equals(FIX_REFERENCE_EVENTS_LS)) { + doReferenceEventsOut(aaf, doc, visible); + } + else if (name.equals(FIX_ANALYSIS_EVENTS_LS)) { + doAnalysisEventsOut(aaf, doc, visible); + } + else if (name.equals(FIX_DEVIATION_LS)) { + doReferenceDeviationOut(aaf, doc, visible); + } + else if (name.equals(LONGITUDINAL_ANNOTATION)) { + doAnnotations( + (FLYSAnnotation) aaf.getData(context), + aaf, + doc, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints (aaf.getData(context), + aaf, + doc, visible, YAXIS.dW.idx); + } + else { + logger.warn("Unknown facet name " + name); + return; + } + } + + @SuppressWarnings("unchecked") + protected void doSectorAverageOut( + ArtifactAndFacet aaf, + Document doc, + boolean visible) + { + logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex()); + + int index = aaf.getFacet().getIndex(); + int sectorNdx = index & 3; + + KMIndex<AnalysisPeriod> kms = + (KMIndex<AnalysisPeriod>)aaf.getData(context); + + if(kms == null) { + return; + } + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); + + for (KMIndex.Entry<AnalysisPeriod> entry: kms) { + double km = entry.getKm(); + AnalysisPeriod ap = entry.getValue(); + QWD qwd = ap.getQSectorAverages()[sectorNdx]; + if (qwd == null) { + continue; + } + double deltaW = qwd.getDeltaW(); + series.add(km, deltaW); + } + + addAxisSeries(series, 0, visible); + + } + + + @SuppressWarnings("unchecked") + protected void doSectorAverageDeviationOut( + ArtifactAndFacet aaf, + Document doc, + boolean visible) + { + logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex()); + + int index = aaf.getFacet().getIndex(); + int sectorNdx = index & 3; + + KMIndex<AnalysisPeriod> kms = + (KMIndex<AnalysisPeriod>)aaf.getData(context); + + if(kms == null) { + return; + } + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); + XYSeries upper = + new StyledXYSeries(aaf.getFacetDescription(), false, doc); + XYSeries lower = + new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); + + + for (KMIndex.Entry<AnalysisPeriod> entry: kms) { + double km = entry.getKm(); + AnalysisPeriod ap = entry.getValue(); + QWD qwd = ap.getQSectorAverages()[sectorNdx]; + double dev = ap.getQSectorStdDev(sectorNdx); + logger.debug("std-dev: " + dev); + if (qwd == null) { + continue; + } + double deltaW = qwd.getDeltaW(); + double up = deltaW + dev; + double lo = deltaW - dev; + upper.add(km, up); + lower.add(km, lo); + } + area.addSeries(upper); + area.addSeries(lower); + + addAreaSeries(area, 0, visible); + } + + + @SuppressWarnings("unchecked") + protected void doReferenceDeviationOut( + ArtifactAndFacet aaf, + Document doc, + boolean visible) + { + logger.debug("doReferenceOut"); + + KMIndex<double[]> kms = + (KMIndex<double[]>)aaf.getData(context); + + if(kms == null) { + return; + } + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); + XYSeries upper = + new StyledXYSeries(aaf.getFacetDescription(), false, doc); + XYSeries lower = + new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); + + + for (KMIndex.Entry<double[]> entry: kms) { + double km = entry.getKm(); + double[] devArray = entry.getValue(); + if (devArray == null) { + continue; + } + double dev = devArray[0]; + double up = dev; + double lo = -dev; + upper.add(km, up, false); + lower.add(km, lo, false); + } + area.addSeries(upper); + area.addSeries(lower); + + Marker marker = new ValueMarker(0); + marker.setStroke(new BasicStroke(2)); + marker.setPaint(Color.BLACK); + addValueMarker(marker); + addAreaSeries(area, 0, visible); + } + + @SuppressWarnings("unchecked") + protected void doAnalysisEventsOut( + ArtifactAndFacet aaf, + Document doc, + boolean visible) + { + logger.debug("doAnalysisEventsOut"); + + KMIndex<QWD> kms = + (KMIndex<QWD>)aaf.getData(context); + + if(kms == null) { + return; + } + + XYSeriesCollection col = new XYSeriesCollection(); + + StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, doc); + + for (KMIndex.Entry<QWD> entry: kms) { + double km = entry.getKm(); + QWD qwd = entry.getValue(); + + series.add(km, qwd.getDeltaW()); + } + col.addSeries(series); + + addAxisDataset(col, 0, visible); + } + + @SuppressWarnings("unchecked") + protected void doReferenceEventsOut( + ArtifactAndFacet aaf, + Document doc, + boolean visible) + { + logger.debug("doReferenceEventOut"); + + KMIndex<QWD> kms = + (KMIndex<QWD>)aaf.getData(context); + + if(kms == null) { + return; + } + + XYSeriesCollection col = new XYSeriesCollection(); + + StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, doc); + + for (KMIndex.Entry<QWD> entry: kms) { + double km = entry.getKm(); + QWD qwd = entry.getValue(); + + series.add(km, qwd.getDeltaW()); + } + col.addSeries(series); + + addAxisDataset(col, 0, visible); + } + + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + @Override + protected ChartGenerator.YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,11 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.flys.exports.ChartInfoGenerator; + +public class FixLongitudinalSectionInfoGenerator extends ChartInfoGenerator { + + public FixLongitudinalSectionInfoGenerator() { + super(new FixLongitudinalSectionGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,569 @@ +package de.intevation.flys.exports.fixings; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.ValueMarker; +import org.jfree.chart.title.TextTitle; +import org.jfree.data.xy.XYSeries; +import org.jfree.ui.RectangleAnchor; +import org.jfree.ui.TextAnchor; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.access.FixAnalysisAccess; +import de.intevation.flys.artifacts.model.DateRange; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.NamedDouble; +import de.intevation.flys.artifacts.model.QWDDateRange; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.fixings.FixFunction; +import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet; +import de.intevation.flys.artifacts.model.fixings.QWD; +import de.intevation.flys.artifacts.model.fixings.QWI; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.exports.ChartGenerator; +import de.intevation.flys.exports.StyledSeriesBuilder; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.JFreeUtil; +import de.intevation.flys.jfree.StickyAxisAnnotation; +import de.intevation.flys.jfree.StyledXYSeries; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.River; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.ThemeUtil; + +/** + * Generator for WQ fixing charts. + * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a> + */ +public class FixWQCurveGenerator +extends FixChartGenerator +implements FacetTypes +{ + private static Logger logger = + Logger.getLogger(FixWQCurveGenerator.class); + + public static final String I18N_CHART_TITLE = + "chart.fixings.wq.title"; + + public static final String I18N_CHART_SUBTITLE = + "chart.fixings.wq.subtitle"; + + public static final String I18N_CHART_SUBTITLE1 = + "chart.fixings.wq.subtitle1"; + + public static final String I18N_XAXIS_LABEL = + "chart.fixings.wq.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.fixings.wq.yaxis.label"; + + public static final String I18N_CHART_TITLE_DEFAULT = + "Fixierungsanalyse"; + + public static final String I18N_XAXIS_LABEL_DEFAULT = + "Q [m\u00B3/s]"; + + public static final String I18N_YAXIS_LABEL_DEFAULT = + "W [NN + m]"; + + public static enum YAXIS { + W(0), + Q(1); + public int idx; + private YAXIS(int c) { + idx = c; + } + } + + + private FLYSArtifact artifact; + + + @Override + public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + String name = aaf.getFacetName(); + logger.debug("doOut: " + name); + + this.artifact = (FLYSArtifact)aaf.getArtifact(); + + if(name.startsWith(FIX_SECTOR_AVERAGE_WQ)) { + doSectorAverageOut(aaf, doc, visible); + } + else if(FIX_ANALYSIS_EVENTS_WQ.equals(name)) { + doAnalysisEventsOut(aaf, doc, visible); + } + else if(FIX_REFERENCE_EVENTS_WQ.equals(name)) { + doReferenceEventsOut(aaf, doc, visible); + } + else if(FIX_WQ_CURVE.equals(name)) { + doWQCurveOut(aaf, doc, visible); + } + else if(FIX_OUTLIER.equals(name)) { + doOutlierOut(aaf, doc, visible); + } + else if(QSECTOR.equals(name)) { + doQSectorOut(aaf, doc, visible); + } + else if(STATIC_WKMS_INTERPOL.equals(name) || + STATIC_WKMS.equals(name) || + HEIGHTMARKS_POINTS.equals(name) ) { + doWAnnotations( + aaf.getData(context), + aaf, + doc, + visible); + } + else if (LONGITUDINAL_W.equals(name) || STATIC_WQ.equals(name)) { + doWQOut(aaf.getData(context), aaf, doc, visible); + } + else if (name.equals(DISCHARGE_CURVE)) { + doDischargeOut( + (WINFOArtifact) aaf.getArtifact(), + aaf.getData(context), + aaf.getFacetDescription(), + doc, + visible); + } + else if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) { + doPoints(aaf.getData(context), + aaf, + doc, visible, YAXIS.W.idx); + } + else { + logger.warn("Unknown facet name " + name); + return; + } + } + + /** Add sector average points to chart */ + protected void doSectorAverageOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doSectorAverageOut"); + + QWDDateRange qwdd = (QWDDateRange) aaf.getData(context); + QWD qwd = qwdd != null ? qwdd.getQWD() : null; + + if(qwd != null) { + addQWSeries(new QWD[] { qwd }, aaf, doc, visible); + } + else { + logger.debug("doSectorAverageOut: qwd == null"); + } + } + + /** Add analysis event points to chart */ + protected void doAnalysisEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doAnalysisEventsOut"); + + QWD qwd = (QWD)aaf.getData(context); + if(qwd != null) { + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + + DateFormat dateFormat = DateFormat.getDateInstance( + DateFormat.SHORT); + + series.add(qwd.getQ(), qwd.getW()); + + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + dateFormat.format(qwd.getDate()), + qwd.getQ(), + qwd.getW()); + textAnnos.add(anno); + + addAxisSeries(series, 0, visible); + if(visible && ThemeUtil.parseShowPointLabel(doc)) { + FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + } + else { + logger.debug("doAnalysisEventsOut: qwds == null"); + } + } + + /** Add reference event points to chart */ + protected void doReferenceEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doReferenceEventsOut"); + + QWI qwd = (QWI)aaf.getData(context); + if(qwd != null) { + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + + DateFormat dateFormat = DateFormat.getDateInstance( + DateFormat.SHORT); + + series.add(qwd.getQ(), qwd.getW()); + + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + dateFormat.format(qwd.getDate()), + qwd.getQ(), + qwd.getW()); + textAnnos.add(anno); + + addAxisSeries(series, 0, visible); + if(visible && ThemeUtil.parseShowPointLabel(doc)) { + FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + } + else { + logger.debug("doAnalysisEventsOut: qwds == null"); + } + } + + protected void doWQCurveOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doWQCurveOut"); + + FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet(); + FixFunction func = (FixFunction)facet.getData( + aaf.getArtifact(), context); + + if (func == null) { + logger.warn("doWQCurveOut: Facet does not contain FixFunction"); + return; + } + + double maxQ = func.getMaxQ(); + + if (maxQ > 0) { + StyledXYSeries series = JFreeUtil.sampleFunction2D( + func.getFunction(), + doc, + aaf.getFacetDescription(), + 500, // number of samples + 0.0 , // start + maxQ); // end + + addAxisSeries(series, 0, visible); + } + else { + logger.warn("doWQCurveOut: maxQ <= 0"); + } + } + + protected void doOutlierOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + logger.debug("doOutlierOut"); + + QWI[] qws = (QWI[])aaf.getData(context); + addQWSeries(qws, aaf, doc, visible); + } + + + /** Add markers for q sectors. */ + protected void doQSectorOut(ArtifactAndFacet aaf, Document theme, boolean visible) { + logger.debug("doQSectorOut"); + if (!visible) { + return; + } + + Object qsectorsObj = aaf.getData(context); + if (qsectorsObj == null || !(qsectorsObj instanceof List)) { + logger.warn("No QSectors coming from data."); + return; + } + + List<?> qsectorsList = (List<?>) qsectorsObj; + if (qsectorsList.size() == 0 || !(qsectorsList.get(0) instanceof NamedDouble)) { + logger.warn("No QSectors coming from data."); + return; + } + + @SuppressWarnings("unchecked") + List<NamedDouble> qsectors = (List<NamedDouble>) qsectorsList; + + for (NamedDouble qsector : qsectors) { + if (Double.isNaN(qsector.getValue())) { + continue; + } + Marker m = new ValueMarker(qsector.getValue()); + m.setPaint(Color.black); + + float[] dashes = ThemeUtil.parseLineStyle(theme); + int size = ThemeUtil.parseLineWidth(theme); + BasicStroke stroke; + if (dashes.length <= 1) { + stroke = new BasicStroke(size); + } + else { + stroke = new BasicStroke(size, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, + 1.0f, + dashes, + 0.0f); + } + m.setStroke(stroke); + + if (ThemeUtil.parseShowLineLabel(theme)) { + m.setLabel(qsector.getName()); + m.setPaint(ThemeUtil.parseTextColor(theme)); + m.setLabelFont(ThemeUtil.parseTextFont(theme)); + } + Color paint = ThemeUtil.parseLineColorField(theme); + if (paint != null) { + m.setPaint(paint); + } + m.setLabelAnchor(RectangleAnchor.TOP_LEFT); + m.setLabelTextAnchor(TextAnchor.TOP_LEFT); + addDomainMarker(m); + } + } + + + /** + * Add W-Annotations to plot. + * @param wqkms actual data (double[][]). + * @param theme theme to use. + */ + protected void doWAnnotations( + Object wqkms, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ) { + Facet facet = aandf.getFacet(); + + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + if (wqkms instanceof double[][]) { + logger.debug("Got double[][]"); + double [][] data = (double [][]) wqkms; + for (int i = 0; i< data[0].length; i++) { + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + } + + doAnnotations(new FLYSAnnotation(facet.getDescription(), xy), + aandf, theme, visible); + } + else { + // Assume its WKms. + logger.debug("Got WKms"); + WKms data = (WKms) wqkms; + + Double ckm = (Double) context.getContextValue(CURRENT_KM); + double location = (ckm != null) + ? ckm.doubleValue() + : getRange()[0]; + double w = StaticWKmsArtifact.getWAtKmLin(data, location); + xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(), + (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + + doAnnotations(new FLYSAnnotation(facet.getDescription(), xy), + aandf, theme, visible); + } + } + + + /** + * Add series with discharge curve to diagram. + */ + protected void doDischargeOut( + WINFOArtifact artifact, + Object o, + String description, + Document theme, + boolean visible) + { + WQKms wqkms = (WQKms) o; + + String gaugeName = wqkms.getName(); + + River river = FLYSUtils.getRiver(artifact); + + if (river == null) { + logger.debug("no river found"); + return; + } + + Gauge gauge = river.determineGaugeByName(gaugeName); + + if (gauge == null) { + logger.debug("no gauge found"); + return; + } + + XYSeries series = new StyledXYSeries(description, theme); + StyledSeriesBuilder.addPointsQW(series, wqkms); + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** + * Add WQ Data to plot. + * @param wqkms data as double[][] + */ + protected void doWQOut( + Object wqkms, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + logger.debug("FixWQCurveGenerator: doWQOut"); + if (wqkms instanceof WQKms) { + WQKms data = (WQKms) wqkms; + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + StyledSeriesBuilder.addPointsQW(series, data); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + else { + double [][] data = (double [][]) wqkms; + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data, true); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + } + + + protected void addQWSeries( + QWI [] qws, + ArtifactAndFacet aaf, + Document theme, + boolean visible + ) { + if (qws == null) { + return; + } + + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + List<XYTextAnnotation> textAnnos = + new ArrayList<XYTextAnnotation>(qws.length); + + DateFormat dateFormat = DateFormat.getDateInstance( + DateFormat.SHORT); + + for (QWI qw: qws) { + series.add(qw.getQ(), qw.getW()); + + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + dateFormat.format(qw.getDate()), + qw.getQ(), + qw.getW()); + textAnnos.add(anno); + } + + addAxisSeries(series, 0, visible); + if (visible && ThemeUtil.parseShowPointLabel(theme)) { + FLYSAnnotation flysAnno = + new FLYSAnnotation(null, null, null, theme); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + } + + @Override + protected String getChartTitle() { + return Resources.format( + context.getMeta(), + I18N_CHART_TITLE, + I18N_CHART_TITLE_DEFAULT, + context.getContextValue(CURRENT_KM)); + } + + @Override + protected String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + @Override + protected String getDefaultChartSubtitle() { + FixAnalysisAccess access = new FixAnalysisAccess(artifact); + DateRange dateRange = access.getDateRange(); + DateRange refRange = access.getReferencePeriod(); + + if (dateRange != null && refRange != null) { + return Resources.format( + context.getMeta(), + I18N_CHART_SUBTITLE, + "", + access.getRiver(), + dateRange.getFrom(), + dateRange.getTo(), + refRange.getFrom(), + refRange.getTo()); + } + + return null; + } + + @Override + protected void addSubtitles(JFreeChart chart) { + String defaultSubtitle = getDefaultChartSubtitle(); + + if (defaultSubtitle == null || defaultSubtitle.length() == 0) { + return; + } + + chart.addSubtitle(new TextTitle(defaultSubtitle)); + + StringBuilder buf = new StringBuilder(); + + // Add analysis periods as additional subtitle + FixAnalysisAccess access = new FixAnalysisAccess(artifact); + DateRange[] aperiods = access.getAnalysisPeriods(); + buf.append(msg("fix.analysis.periods")); + buf.append(": "); + for(int n = 0; n < aperiods.length; n++) { + buf.append( + Resources.format( + context.getMeta(), + I18N_CHART_SUBTITLE1, + "", + aperiods[n].getFrom(), + aperiods[n].getTo())); + if(n + 1 < aperiods.length) { + buf.append("; "); + } + } + + chart.addSubtitle(new TextTitle(buf.toString())); + } + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + @Override + protected String getDefaultYAxisLabel(int pos) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + @Override + protected ChartGenerator.YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixWQCurveInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,17 @@ +package de.intevation.flys.exports.fixings; + +import de.intevation.flys.exports.ChartInfoGenerator; + +/** + * A ChartInfoGenerator that generates meta information for specific fixing + * analysis W/Q curves. + * + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class FixWQCurveInfoGenerator extends ChartInfoGenerator { + + public FixWQCurveInfoGenerator() { + super(new FixWQCurveGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,115 @@ +package de.intevation.flys.exports.fixings; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult; + +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.flys.exports.AbstractExporter; + +import java.io.IOException; +import java.io.OutputStream; + +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +public class ParametersExporter +extends AbstractExporter +{ + private static Logger log = Logger.getLogger(ParametersExporter.class); + + protected List<Parameters> parametersList; + + @Override + public void init(Document request, OutputStream out, CallContext context) { + log.debug("ParametersExporter.init"); + super.init(request, out, context); + parametersList = new ArrayList<Parameters>(); + } + + @Override + protected void addData(Object d) { + log.debug("ParametersExporter.addData"); + if (!(d instanceof CalculationResult)) { + log.warn("Invalid data type"); + return; + } + + Object data = ((CalculationResult)d).getData(); + if (!(data instanceof FixAnalysisResult)) { + log.warn("Invalid data stored in result."); + return; + } + + FixAnalysisResult result = (FixAnalysisResult)data; + parametersList.add(result.getParameters()); + } + + @Override + public void generate() + throws IOException + { + log.debug("ParametersExporter.generate"); + + if (facet == null) { + throw new IOException("invalid (null) facet for exporter"); + } + + if (facet.equals(FIX_PARAMETERS)) { + generateCSV(); + } + else { + throw new IOException( + "invalid facet for exporter: '" + facet + "'"); + } + } + + @Override + protected void writeCSVData(final CSVWriter writer) throws IOException { + + if (parametersList.isEmpty()) { + return; + } + + Parameters parameters = parametersList.get(0); + writer.writeNext(parameters.getColumnNames()); + + final int numColumns = parameters.getNumberColumns(); + + parameters.visit(new Parameters.Visitor() { + + String [] row = new String[numColumns]; + + NumberFormat format = NumberFormat.getInstance( + Resources.getLocale(context.getMeta())); + + @Override + public void visit(double [] data) { + for (int i = 0; i < data.length; ++i) { + row[i] = format.format(data[i]); + } + writer.writeNext(row); + } + }, new double[numColumns]); + + writer.flush(); + } + + @Override + protected void writePDF(OutputStream out) { + // TODO: Implement me! + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,216 @@ +package de.intevation.flys.exports.minfo; + +import gnu.trove.TDoubleArrayList; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +import au.com.bytecode.opencsv.CSVWriter; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.minfo.BedDiameterResult; +import de.intevation.flys.artifacts.model.minfo.BedParametersResult; +import de.intevation.flys.artifacts.model.minfo.BedQualityResult; +import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult; +import de.intevation.flys.exports.AbstractExporter; +import de.intevation.flys.utils.Formatter; + + +public class BedQualityExporter +extends AbstractExporter +{ + /** Private logger. */ + private static Logger logger = Logger.getLogger(BedQualityExporter.class); + + private static final String CSV_HEADER_KM = "export.minfo.bedquality.km"; + private static final String CSV_HEADER_DENSITY_CAP = + "export.minfo.bedquality.density_cap"; + private static final String CSV_HEADER_DENSITY_SUB = + "export.minfo.bedquality.density_sub"; + private static final String CSV_HEADER_POROSITY_CAP = + "export.minfo.bedquality.porosity_cap"; + private static final String CSV_HEADER_POROSITY_SUB = + "export.minfo.bedquality.porosity_sub"; + private static final String CSV_HEADER_BEDLOAD = + "export.minfo.bedquality.bedload"; + private static final String CSV_HEADER_BED_CAP = + "export.minfo.bedquality.bed_cap"; + private static final String CSV_HEADER_BED_SUB = + "export.minfo.bedquality.bed_sub"; + + private BedQualityResult[] results; + + @Override + public void init(Document request, OutputStream out, CallContext context) { + logger.debug("BedQualityExporter.init"); + super.init(request, out, context); + results = new BedQualityResult[0]; + } + + @Override + protected void writeCSVData(CSVWriter writer) throws IOException { + // TODO Auto-generated method stub + writeCSVHeader(writer); + + NumberFormat kmf = Formatter.getCalculationKm(context.getMeta()); + + TDoubleArrayList kms = new TDoubleArrayList(); + int cols = 1; + for (int i = 0; i < results.length; i++) { + BedDiameterResult[] beds = results[i].getBedResults(); + for (int j = 0; j < beds.length; j++) { + TDoubleArrayList bkms = beds[j].getKms(); + for (int k = 0; k < bkms.size(); k++) { + if (!kms.contains(bkms.get(k))) { + kms.add(bkms.get(k)); + } + } + } + BedloadDiameterResult[] loads = results[i].getBedloadResults(); + for (int j = 0; j < loads.length; j++) { + TDoubleArrayList lkms = loads[i].getKms(); + for (int k = 0; k < lkms.size(); k++) { + if (!kms.contains(lkms.get(k))) { + kms.add(lkms.get(k)); + } + } + } + cols += beds.length * 2; + cols += loads.length; + if (beds.length > 0) { + cols += 4; + } + } + + kms.sort(); + List<double[]> rows = new LinkedList<double[]>(); + for (int i = 0; i < kms.size(); i++) { + double[] row = new double[cols]; + double km = kms.get(i); + row[0] = km; + for (int j = 0; j < results.length; j++) { + BedloadDiameterResult[] loads = results[j].getBedloadResults(); + + for(int k = 0; k < loads.length; k++) { + // k + 1: shift km column. + // j* loads.length: shift periods. + row[(k + 1) + (j * loads.length)] = + loads[k].getDiameter(km); + } + BedDiameterResult[] beds = results[j].getBedResults(); + for (int k = 0; k < beds.length; k++) { + // k + 1: shift km column. + // j * beds.length: shift periods. + // loads.length * results.length: shift bed load columns. + int ndx = (k + 1) + (j * beds.length) + (loads.length * results.length); + row[ndx] = beds[k].getDiameterCap(km); + row[ndx + 1] = beds[k].getDiameterSub(km); + } + BedParametersResult[] params = results[j].getParameters(); + for(int k = 0; k < params.length; k++) { + // loads.length + (beds.lenght * 2) * (j + 1): shift bed and bedload columns. + int ndx = 1 + (loads.length + (beds.length * 2) * (j + 1)); + row[ndx] = params[k].getLoadDensityCap(km); + row[ndx + 1] = params[k].getLoadDensitySub(km); + row[ndx + 2] = params[k].getPorosityCap(km); + row[ndx + 3] = params[k].getPorositySub(km); + } + } + rows.add(row); + } + for (double[] d : rows) { + logger.debug(Arrays.toString(d)); + List<String> cells = new LinkedList<String>(); + for (int i = 0; i < d.length; i++) { + if (!Double.isNaN(d[i])) { + NumberFormat nf = Formatter.getFormatter(context, 1, 3); + cells.add(nf.format(d[i])); + } + else { + cells.add(""); + } + } + writer.writeNext(cells.toArray(new String[cells.size()])); + } + } + + @Override + protected void writePDF(OutputStream out) { + // TODO Auto-generated method stub + + } + + @Override + protected void addData(Object data) { + // TODO Auto-generated method stub + logger.debug("addData()"); + if (!(data instanceof CalculationResult)) { + logger.warn("Invalid data type."); + return; + } + Object[] d = (Object[])((CalculationResult)data).getData(); + + if (!(d instanceof BedQualityResult[])) { + logger.warn("Invalid result object."); + return; + } + results = (BedQualityResult[])d; + } + + protected void writeCSVHeader(CSVWriter writer) { + logger.debug("writeCSVHeader()"); + + List<String> header = new LinkedList<String>(); + if (results != null) { + header.add(msg(CSV_HEADER_KM, "km")); + for (int i = 0; i < results.length; i++) { + DateFormat df = Formatter.getDateFormatter(context.getMeta(), "dd.MM.yyyy"); + String d1 = df.format(results[i].getDateRange().getFrom()); + String d2 = df.format(results[i].getDateRange().getTo()); + BedloadDiameterResult[] loads = results[i].getBedloadResults(); + BedDiameterResult[] beds = results[i].getBedResults(); + BedParametersResult[] params = results[i].getParameters(); + for (int j = 0; j < loads.length; j++) { + header.add(msg(CSV_HEADER_BEDLOAD, CSV_HEADER_BEDLOAD) + + " - " + + msg(loads[j].getType().toString(), + loads[j].getType().toString()) + " - " + + d1 + "-" + d2); + } + for (int j = 0; j < beds.length; j++) { + header.add(msg(CSV_HEADER_BED_CAP, CSV_HEADER_BED_CAP) + " - " + + msg(beds[j].getType().toString(), + beds[j].getType().toString()) + " - " + + d1 + "-" + d2); + header.add(msg(CSV_HEADER_BED_SUB, CSV_HEADER_BED_SUB) + " - " + + msg(beds[j].getType().toString(), + beds[j].getType().toString()) + " - " + + d1 + "-" + d2); + } + if (params.length > 0) { + header.add( + msg(CSV_HEADER_DENSITY_CAP, CSV_HEADER_DENSITY_CAP));// + + //" - " + d1 + "-" + d2); + header.add( + msg(CSV_HEADER_DENSITY_SUB, CSV_HEADER_DENSITY_SUB)); //+ + //" - " + d1 + "-" + d2); + header.add( + msg(CSV_HEADER_POROSITY_CAP, CSV_HEADER_POROSITY_CAP)); //+ + //" - " + d1 + "-" + d2); + header.add( + msg(CSV_HEADER_POROSITY_SUB, CSV_HEADER_POROSITY_SUB));// + + //" - " + d1 + "-" + d2); + } + } + } + writer.writeNext(header.toArray(new String[header.size()])); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,273 @@ +package de.intevation.flys.exports.minfo; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; +import org.w3c.dom.Document; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.minfo.BedDiameterResult; +import de.intevation.flys.artifacts.model.minfo.BedParametersResult; +import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult; +import de.intevation.flys.exports.StyledSeriesBuilder; +import de.intevation.flys.exports.XYChartGenerator; +import de.intevation.flys.jfree.StyledXYSeries; + + +/** + * An OutGenerator that generates bed quality charts. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedQualityGenerator extends XYChartGenerator implements FacetTypes { + + public enum YAXIS { + W(0), P(1), D(2); + + protected int idx; + + private YAXIS(int c) { + idx = c; + } + } + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(BedQualityGenerator.class); + + public static final String I18N_CHART_TITLE = "chart.bedquality.title"; + public static final String I18N_XAXIS_LABEL = "chart.bedquality.xaxis.label"; + public static final String I18N_YAXIS_LABEL = "chart.bedquality.yaxis.label"; + public static final String I18N_SECOND_YAXIS_LABEL = "chart.bedquality.yaxis.label.porosity"; + public static final String I18N_THIRD_YAXIS_LABEL = "chart.bedquality.yaxis.label.diameter"; + + public static final String I18N_CHART_TITLE_DEFAULT = "Sohlen Längsschnitt"; + public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km"; + public static final String I18N_YAXIS_LABEL_DEFAULT = "Durchmesser [m]"; + public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Porosität [%]"; + public static final String I18N_THIRD_YAXIS_LABEL_DEFAULT = "Dichte [t/m^3]"; + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + /** + * Returns the default title for this chart. + * + * @return the default title for this chart. + */ + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); + } + + /** + * Get internationalized label for the x axis. + */ + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); + } + + @Override + protected String getDefaultYAxisLabel(int index) { + String label = "default"; + + if (index == YAXIS.W.idx) { + label = getWAxisLabel(); + } + else if (index == YAXIS.P.idx) { + label = getPAxisLabel(); + } + else if (index == YAXIS.D.idx) { + label = getDAxisLabel(); + } + + return label; + } + + /** + * Get internationalized label for the y axis displaying the diameter. + */ + protected String getWAxisLabel() { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); + } + + /** + * Get internationalized label for the y axis displaying the porosity. + */ + protected String getPAxisLabel() { + return msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT); + } + + /** + * Get internationalized label for the y axis displaying the density. + */ + protected String getDAxisLabel() { + return msg(I18N_THIRD_YAXIS_LABEL, I18N_THIRD_YAXIS_LABEL_DEFAULT); + } + + /** + * Produce output. + * + * @param artifactAndFacet + * current facet. + * @param attr + * theme for facet + */ + public void doOut(ArtifactAndFacet artifactAndFacet, Document attr, + boolean visible) { + String name = artifactAndFacet.getFacetName(); + + logger.debug("BedQualityGenerator.doOut: " + name); + + if (name == null) { + logger.error("No facet name for doOut(). No output generated!"); + return; + } + + Facet facet = artifactAndFacet.getFacet(); + + if (facet == null) { + return; + } + + // TODO BED_QUALITY_BED_DIAMETER_TOPLAYER + if (name.equals(BED_QUALITY_BED_DIAMETER_TOPLAYER)) { + doBedDiameterTopLayerOut( + (BedDiameterResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (name.equals(BED_QUALITY_BED_DIAMETER_SUBLAYER)) { + doBedDiameterSubLayerOut( + (BedDiameterResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + // TODO BED_QUALITY_BED_DIAMETER_SUBLAYER + else if (name.equals(BED_QUALITY_BEDLOAD_DIAMETER)) { + doBedLoadDiameterOut( + (BedloadDiameterResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (name.equals(BED_QUALITY_POROSITY_TOPLAYER)) { + doPorosityTopLayerOut( + (BedParametersResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (name.equals(BED_QUALITY_POROSITY_SUBLAYER)) { + doPorositySubLayerOut( + (BedParametersResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER)) { + doDensityTopLayerOut( + (BedParametersResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER)) { + doDensitySubLayerOut( + (BedParametersResult) artifactAndFacet.getData(context), + artifactAndFacet, attr, visible); + } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints(artifactAndFacet.getData(context), artifactAndFacet, attr, + visible, YAXIS.W.idx); + } + else { + logger.warn("Unknown facet name: " + name); + return; + } + } + + protected void doBedDiameterTopLayerOut(BedDiameterResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doBedDiameterTopLayerOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data.getDiameterCapData(), true); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + protected void doBedDiameterSubLayerOut(BedDiameterResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doBedDiameterSubLayerOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data.getDiameterSubData(), true); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + protected void doBedLoadDiameterOut(BedloadDiameterResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doBedLoadDiameterOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data.getDiameterData(), true); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + protected void doPorosityTopLayerOut(BedParametersResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doPorosityTopLayerOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getPorosityCapData(), + true); + + addAxisSeries(series, YAXIS.P.idx, visible); + } + + protected void doPorositySubLayerOut(BedParametersResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doPorositySubLayerOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getPorositySubData(), + true); + + addAxisSeries(series, YAXIS.P.idx, visible); + } + + protected void doDensityTopLayerOut(BedParametersResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doDensityOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getDensityCapData(), + true); + + addAxisSeries(series, YAXIS.D.idx, visible); + } + + protected void doDensitySubLayerOut(BedParametersResult data, + ArtifactAndFacet aandf, Document theme, boolean visible) { + logger.debug("BedQuality.doDensityOut"); + + XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPoints(series, data.getDensitySubData(), + true); + + addAxisSeries(series, YAXIS.D.idx, visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedQualityInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,18 @@ +package de.intevation.flys.exports.minfo; + +import de.intevation.flys.exports.ChartInfoGenerator; + + +/** + * A ChartInfoGenerator that generates meta information for specific computed + * bed quality curves. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class BedQualityInfoGenerator extends ChartInfoGenerator { + + public BedQualityInfoGenerator() { + super(new BedQualityGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,238 @@ +package de.intevation.flys.exports.sq; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.JFreeChart; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Settings; +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabaseException; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.ArtifactNamespaceContext; +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.collections.FLYSArtifactCollection; +import de.intevation.flys.exports.ChartGenerator; +import de.intevation.flys.exports.OutGenerator; +import de.intevation.flys.exports.OutputHelper; + +public class SQOverviewGenerator +implements OutGenerator +{ + private static Logger logger = Logger.getLogger(SQOverviewGenerator.class); + + public static final String XPATH_CHART_SIZE = + "/art:action/art:attributes/art:size"; + + protected FLYSArtifactCollection collection; + + protected Artifact master; + + protected Settings settings; + + protected Document request; + + protected OutputStream out; + + protected CallContext context; + + protected List<JFreeChart> charts; + + /** + * Produce output. + * @param artifactAndFacet current facet and artifact. + * @param attr theme for facet + */ + @Override + public void doOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + logger.debug("doOut()"); + + String name = artifactAndFacet.getData(context).toString(); + if(name != null) { + logger.debug("name: " + name); + ChartGenerator g = + (ChartGenerator)FLYSContext.getOutGenerator( + context, + name, + null); + + if (g == null) { + logger.debug("generator is null."); + return; + } + + OutputHelper helper = new OutputHelper(master.identifier()); + Document collectionAttribute = collection.getAttribute(); + + try { + Document cAttr = getAttribute(context, collectionAttribute, name); + g.init(request, out, context); + + helper.doOut(g, name, name, cAttr, context); + JFreeChart chart = g.generateChart(); + chart.removeLegend(); + charts.add(chart); + } + catch (IOException e) { + logger.warn(e); + } + catch (ArtifactDatabaseException e) { + logger.warn(e); + } + } + } + + @Override + public void init(Document request, OutputStream out, CallContext context) { + this.request = request; + this.out = out; + this.context = context; + charts = new ArrayList<JFreeChart>(); + } + + @Override + public void setMasterArtifact(Artifact master) { + this.master = master; + } + + @Override + public void setCollection(FLYSArtifactCollection collection) { + this.collection = collection; + } + + @Override + public void generate() throws IOException { + logger.debug("SQOverviewGenerator.generate"); + + int[] size = getSize(); + + if (size == null) { + size = new int[] {400, 600}; + } + BufferedImage result = + new BufferedImage(size[0], size[1], BufferedImage.TYPE_INT_RGB); + for (int i = 0; i < charts.size(); i++) { + logger.debug("index: " + i); + JFreeChart chart = charts.get(i); + ChartRenderingInfo info = new ChartRenderingInfo(); + BufferedImage img = + chart.createBufferedImage(size[0]/2, size[1]/3, info); + int horPos = 0; + int vertPos = 0; + if (i % 2 == 1) { + horPos = size[0]/2; + } + if (i > 1) { + vertPos = (size[1] / 3) * (i / 2); + } + result.createGraphics().drawImage(img, horPos, vertPos, null); + } + ImageIO.write(result, "png", out); + } + + @Override + public void setSettings(Settings settings) { + this.settings = settings; + } + + @Override + public Settings getSettings() { + return this.settings; + } + + + /** + * Returns the "attribute" (part of description document) for a specific + * output type. + * + * @param context The CallContext object. + * @param attr The xml attribute saved at the collection. + * @param output The name of the desired output type. + * + * @return the attribute for the desired output type. + */ + protected Document getAttribute( + CallContext context, + Document attr, + String output) + throws ArtifactDatabaseException + { + logger.debug("find specific XML node for Output: " + output); + + Map<String, String> vars = new HashMap<String, String>(); + vars.put("output", output); + + Node out = (Node) XMLUtils.xpath( + attr, + "art:attribute/art:outputs/art:output[@name=$output]", + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE, + vars); + + if (out != null) { + Document o = XMLUtils.newDocument(); + o.appendChild(o.importNode(out, true)); + + return o; + } + + return null; + } + + + /** + * Returns the size of a chart export as array which has been specified by + * the incoming request document. + * + * @return the size of a chart as [width, height] or null if no width or + * height are given in the request document. + */ + protected int[] getSize() { + int[] size = new int[2]; + + Element sizeEl = (Element)XMLUtils.xpath( + request, + XPATH_CHART_SIZE, + XPathConstants.NODE, + ArtifactNamespaceContext.INSTANCE); + + if (sizeEl != null) { + String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + String w = sizeEl.getAttributeNS(uri, "width"); + String h = sizeEl.getAttributeNS(uri, "height"); + + if (w.length() > 0 && h.length() > 0) { + try { + size[0] = Integer.parseInt(w); + size[1] = Integer.parseInt(h); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for chart width/height."); + } + } + } + + return size[0] > 0 && size[1] > 0 ? size : null; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,162 @@ +package de.intevation.flys.exports.sq; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; + +import au.com.bytecode.opencsv.CSVWriter; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.model.CalculationResult; + +import de.intevation.flys.artifacts.model.sq.SQFractionResult; +import de.intevation.flys.artifacts.model.sq.SQResult; +import de.intevation.flys.artifacts.model.Parameters; + +import de.intevation.flys.exports.AbstractExporter; + +import org.apache.log4j.Logger; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQRelationExporter extends AbstractExporter { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(SQRelationExporter.class); + + + public static final String CSV_PARAMETER = + "export.sqrelation.csv.header.parameter"; + + public static final String CSV_STATION = + "export.sqrelation.csv.header.station"; + + public static final String CSV_KM = + "export.sqrelation.csv.header.km"; + + public static final String CSV_FUNCTION = + "export.sqrelation.csv.header.function"; + + public static final String CSV_GAUGE = + "export.sqrelation.csv.header.gauge"; + + public static final String CSV_COEFF_A = + "export.sqrelation.csv.header.coeff.a"; + + public static final String CSV_COEFF_B = + "export.sqrelation.csv.header.coeff.b"; + + public static final String CSV_COEFF_Q = + "export.sqrelation.csv.header.coeff.q"; + + public static final String CSV_COEFF_R = + "export.sqrelation.csv.header.coeff.r"; + + public static final String CSV_N_TOTAL = + "export.sqrelation.csv.header.n.total"; + + public static final String CSV_N_OUTLIERS = + "export.sqrelation.csv.header.n.outliers"; + + public static final String CSV_C_DUAN = + "export.sqrelation.csv.header.c.duan"; + + public static final String CSV_C_FERGUSON = + "export.sqrelation.csv.header.c.ferguson"; + + public static final String CSV_VARIANCE = + "export.sqrelation.csv.header.variance"; + + + protected List<SQResult []> data; + + + public void init(Document request, OutputStream out, CallContext cc) { + super.init(request, out, cc); + data = new ArrayList<SQResult []>(); + } + + + @Override + protected void addData(Object d) { + if (d instanceof CalculationResult) { + d = ((CalculationResult)d).getData(); + if (d instanceof SQResult []) { + data.add((SQResult [])d); + } + } + } + + protected void writeCSVHeader(CSVWriter writer) { + writer.writeNext(new String[] { + msg(CSV_KM , CSV_KM), + msg(CSV_PARAMETER, CSV_PARAMETER), + msg(CSV_COEFF_A , CSV_COEFF_A), + msg(CSV_COEFF_B , CSV_COEFF_B), + msg(CSV_N_TOTAL , CSV_N_TOTAL), + msg(CSV_N_OUTLIERS, CSV_N_OUTLIERS), + msg(CSV_VARIANCE , CSV_VARIANCE) + }); + } + + @Override + protected void writeCSVData(CSVWriter writer) { + logger.debug("writeCSVData"); + + writeCSVHeader(writer); + + for (SQResult [] results: data) { + for (SQResult result: results) { + data2CSV(writer, result); + } + } + } + + protected void data2CSV(CSVWriter writer, SQResult result) { + logger.debug("data2CSV"); + + // TODO: i18n + String km = String.valueOf(result.getKm()); + + for (int i = 0; i < SQResult.NUMBER_FRACTIONS; ++i) { + SQFractionResult fraction = result.getFraction(i); + + String name = result.getFractionName(i); + + Parameters parameters = fraction.getParameters(); + + if (parameters == null) { + continue; + } + + double a = parameters.getValue(0, "a"); + double b = parameters.getValue(0, "b"); + double sd = Math.sqrt(parameters.getValue(0, "std_dev")); + int o = fraction.totalNumOutliers(); + int t = fraction.numMeasurements() + o; + + writer.writeNext(new String[] { + km, + name, + String.valueOf(a), + String.valueOf(b), + String.valueOf(t), + String.valueOf(o), + String.valueOf(sd) + }); + } + } + + + @Override + protected void writePDF(OutputStream out) { + logger.debug("writePDF"); + logger.error("NOT IMPLEMENTED: writePDF"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,203 @@ +package de.intevation.flys.exports.sq; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.flys.artifacts.model.FacetTypes; + +import de.intevation.flys.artifacts.model.sq.SQ; +import de.intevation.flys.artifacts.model.sq.SQFunction; + +import de.intevation.flys.exports.XYChartGenerator; + +import de.intevation.flys.jfree.JFreeUtil; +import de.intevation.flys.jfree.StyledXYSeries; + +import org.apache.log4j.Logger; + +import org.jfree.chart.axis.LogarithmicAxis; +import org.jfree.chart.axis.NumberAxis; + +import org.jfree.data.xy.XYSeries; + +import org.w3c.dom.Document; + +/** + * An OutGenerator that generates charts for MINFO sq relation. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQRelationGenerator +extends XYChartGenerator +implements FacetTypes +{ + public enum YAXIS { + S(0); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + + + public static final String I18N_XAXIS_LABEL = + "chart.sq_relation.xaxis.label"; + + public static final String I18N_YAXIS_LABEL = + "chart.sq_relation.yaxis.label"; + + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(SQRelationGenerator.class); + + + @Override + protected YAxisWalker getYAxisWalker() { + return new YAxisWalker() { + @Override + public int length() { + return YAXIS.values().length; + } + + @Override + public String getId(int idx) { + YAXIS[] yaxes = YAXIS.values(); + return yaxes[idx].toString(); + } + }; + } + + + @Override + public String getDefaultChartTitle() { + return "TODO: CHART TITLE"; + } + + + @Override + protected String getDefaultXAxisLabel() { + return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); + } + + + @Override + protected String getDefaultYAxisLabel(int index) { + return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); + } + + + @Override + protected NumberAxis createXAxis(String label) { + return new LogarithmicAxis(label); + } + + + @Override + protected NumberAxis createYAxis(int index) { + return new LogarithmicAxis(getDefaultYAxisLabel(index)); + } + + + @Override + public void doOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + logger.debug("doOut"); + + Facet facet = artifactAndFacet.getFacet(); + String name = facet != null ? facet.getName() : null; + + if (name == null || name.length() == 0) { + logger.warn("Invalid facet with no name given!"); + return; + } + + if (IS.SQ_CURVE(name)) { + doSQCurveOut(artifactAndFacet, attr, visible); + } + else if (IS.SQ_MEASUREMENT(name)) { + doSQOut(artifactAndFacet, attr, visible); + } + else if (IS.SQ_OUTLIER(name)) { + doSQOut(artifactAndFacet, attr, visible); + } + } + + + protected void doSQCurveOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + String desc = artifactAndFacet.getFacetDescription(); + logger.debug("doSQCurveOut: " + desc); + + Facet f = artifactAndFacet.getFacet(); + SQFunction func = (SQFunction) artifactAndFacet.getData(context); + + if (func == null) { + return; + } + + XYSeries series = JFreeUtil.sampleFunction2D( + func.getFunction(), + attr, + desc, + 500, + Math.max(func.getMinQ(), 0.01), + Math.max(func.getMaxQ(), 0.02)); + + if (logger.isDebugEnabled()) { + logger.debug("Series '" + desc + "' has " + + series.getItemCount() + " items."); + + logger.debug(" -> min x = " + series.getMinX()); + logger.debug(" -> max x = " + series.getMaxX()); + logger.debug(" -> min y = " + series.getMinY()); + logger.debug(" -> max y = " + series.getMaxY()); + } + + addAxisSeries(series, YAXIS.S.idx, visible); + } + + + protected void doSQOut( + ArtifactAndFacet artifactAndFacet, + Document attr, + boolean visible + ) { + String desc = artifactAndFacet.getFacetDescription(); + logger.debug("doSQOut: " + desc); + + Facet f = artifactAndFacet.getFacet(); + SQ[] sqs = (SQ[]) artifactAndFacet.getData(context); + if (sqs == null) { + logger.debug("No SQs found for facet"); + return; + } + XYSeries series = new StyledXYSeries(desc, attr); + + for (SQ sq: sqs) { + double q = sq.getQ(); + double s = sq.getS(); + if (s > 0d && q > 0d) { + series.add(q, s, false); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("Series '" + desc + "' has " + + series.getItemCount() + " items."); + + logger.debug(" -> min x = " + series.getMinX()); + logger.debug(" -> max x = " + series.getMaxX()); + logger.debug(" -> min y = " + series.getMinY()); + logger.debug(" -> max y = " + series.getMaxY()); + } + + addAxisSeries(series, YAXIS.S.idx, visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorA.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorA extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_a.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorB.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorB extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_b.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorC.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorC extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_c.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorD.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorD extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_d.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorE.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorE extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_e.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorF.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.exports.sq; + + +public class SQRelationGeneratorF extends SQRelationGenerator { + + public static final String I18N_CHART_TITLE = + "chart.sq_relation_f.title"; + + + @Override + public String getDefaultChartTitle() { + return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/sq/SQRelationInfoGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,19 @@ +package de.intevation.flys.exports.sq; + +import de.intevation.flys.exports.ChartInfoGenerator; + + +/** + * A ChartInfoGenerator that generates meta information for specific + * sq relation charts. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SQRelationInfoGenerator +extends ChartInfoGenerator +{ + public SQRelationInfoGenerator() { + super(new SQRelationGenerator()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/java2d/NOPGraphics2D.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,528 @@ +package de.intevation.flys.java2d; + +import java.util.Map; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Image; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Paint; +import java.awt.GraphicsConfiguration; +import java.awt.Stroke; +import java.awt.Rectangle; +import java.awt.Font; +import java.awt.FontMetrics; + +import java.awt.image.RenderedImage; + +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; + +import java.awt.image.renderable.RenderableImage; + +import java.awt.geom.AffineTransform; + +import java.text.AttributedCharacterIterator; + +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; + +import java.awt.RenderingHints; + +public final class NOPGraphics2D +extends Graphics2D +{ + private Graphics2D parent; + + public NOPGraphics2D(Graphics2D parent) { + this.parent = parent; + } + + @Override + public final void addRenderingHints(Map<?,?> hints) { + parent.addRenderingHints(hints); + } + + @Override + public final void clip(Shape s) { + } + + @Override + public final void draw(Shape s) { + } + + @Override + public final void drawGlyphVector(GlyphVector g, float x, float y) { + } + + @Override + public final void drawImage( + BufferedImage img, + BufferedImageOp op, + int x, + int y + ) { + } + + @Override + public final boolean drawImage( + Image img, + AffineTransform xform, + ImageObserver obs + ) { + return true; + } + + @Override + public final void drawRenderableImage( + RenderableImage img, + AffineTransform xform + ) { + } + + @Override + public final void drawRenderedImage( + RenderedImage img, + AffineTransform xform + ) { + } + + @Override + public final void drawString( + AttributedCharacterIterator iterator, + float x, + float y + ) { + } + + @Override + public final void drawString( + AttributedCharacterIterator iterator, + int x, + int y + ) { + } + + @Override + public final void drawString(String str, float x, float y) { + } + + @Override + public final void drawString(String str, int x, int y) { + } + + @Override + public final void fill(Shape s) { + } + + @Override + public final Color getBackground() { + return parent.getBackground(); + } + + @Override + public final Composite getComposite() { + return parent.getComposite(); + } + + @Override + public final GraphicsConfiguration getDeviceConfiguration() { + return parent.getDeviceConfiguration(); + } + + @Override + public final FontRenderContext getFontRenderContext() { + return parent.getFontRenderContext(); + } + + @Override + public final Paint getPaint() { + return parent.getPaint(); + } + + @Override + public final Object getRenderingHint(RenderingHints.Key hintKey) { + return parent.getRenderingHint(hintKey); + } + + @Override + public final RenderingHints getRenderingHints() { + return parent.getRenderingHints(); + } + + @Override + public final Stroke getStroke() { + return parent.getStroke(); + } + + @Override + public final AffineTransform getTransform() { + return parent.getTransform(); + } + + @Override + public final boolean hit(Rectangle rect, Shape s, boolean onStroke) { + return parent.hit(rect, s, onStroke); + } + + @Override + public final void rotate(double theta) { + parent.rotate(theta); + } + + @Override + public final void rotate(double theta, double x, double y) { + parent.rotate(theta); + } + + @Override + public final void scale(double sx, double sy) { + parent.scale(sx, sy); + } + + @Override + public final void setBackground(Color color) { + parent.setBackground(color); + } + + @Override + public final void setComposite(Composite comp) { + parent.setComposite(comp); + } + + @Override + public final void setPaint(Paint paint) { + parent.setPaint(paint); + } + + @Override + public final void setRenderingHint( + RenderingHints.Key hintKey, + Object hintValue + ) { + parent.setRenderingHint(hintKey, hintValue); + } + + @Override + public final void setRenderingHints(Map<?,?> hints) { + parent.setRenderingHints(hints); + } + + @Override + public final void setStroke(Stroke s) { + parent.setStroke(s); + } + + @Override + public final void setTransform(AffineTransform Tx) { + parent.setTransform(Tx); + } + + + @Override + public final void shear(double shx, double shy) { + parent.shear(shx, shy); + } + + @Override + public final void transform(AffineTransform Tx) { + parent.transform(Tx); + } + + @Override + public final void translate(double tx, double ty) { + parent.translate(tx, ty); + } + + @Override + public final void translate(int tx, int ty) { + parent.translate(tx, ty); + } + + @Override + public final void dispose() { + parent.dispose(); + } + + @Override + public final boolean drawImage( + Image img, + int x, + int y, + int width, + int height, + Color bgcolor, + ImageObserver observer + ) { + return true; + } + + @Override + public final boolean drawImage( + Image img, + int dx1, + int dy1, + int dx2, + int dy2, + int sx1, + int sy1, + int sx2, + int sy2, + Color bgcolor, + ImageObserver observer + ) { + return true; + } + + @Override + public final boolean drawImage( + Image img, + int dx1, + int dy1, + int dx2, + int dy2, + int sx1, + int sy1, + int sx2, + int sy2, + ImageObserver observer + ) { + return true; + } + + @Override + public final boolean drawImage( + Image img, + int x, + int y, + Color bgcolor, + ImageObserver observer + ) { + return true; + } + + @Override + public final boolean drawImage( + Image img, + int x, + int y, + int width, + int height, + ImageObserver observer + ) { + return true; + } + + @Override + public final boolean drawImage( + Image img, + int x, + int y, + ImageObserver observer + ) { + return true; + } + + @Override + public final void fillPolygon( + int [] xPoints, + int [] yPoints, + int nPoints + ) { + } + + @Override + public final void drawPolygon( + int [] xPoints, + int [] yPoints, + int nPoints + ) { + } + + @Override + public final void drawPolyline( + int [] xPoints, + int [] yPoints, + int nPoints + ) { + } + + @Override + public final void fillArc( + int x, + int y, + int width, + int height, + int startAngle, + int arcAngle + ) { + } + + @Override + public final void drawArc( + int x, + int y, + int width, + int height, + int startAngle, + int arcAngle + ) { + } + + @Override + public final void fillOval( + int x, + int y, + int width, + int height + ) { + } + + @Override + public final void drawOval( + int x, + int y, + int width, + int height + ) { + } + + @Override + public final void fillRoundRect( + int x, + int y, + int width, + int height, + int arcWidth, + int arcHeight + ) { + } + + @Override + public final void drawRoundRect( + int x, + int y, + int width, + int height, + int arcWidth, + int arcHeight + ) { + } + + @Override + public final void clearRect( + int x, + int y, + int width, + int height + ) { + } + + @Override + public final void fillRect( + int x, + int y, + int width, + int height + ) { + } + + @Override + public final void drawLine( + int x1, + int y1, + int x2, + int y2 + ) { + } + + @Override + public final void copyArea( + int x, + int y, + int width, + int height, + int dx, + int dy + ) { + } + + @Override + public final void setClip( + int x, + int y, + int width, + int height + ) { + parent.setClip(x, y, width, height); + } + + @Override + public final void setClip(Shape shape) { + parent.setClip(shape); + } + + @Override + public final Shape getClip() { + return parent.getClip(); + } + + @Override + public final void clipRect( + int x, + int y, + int width, + int height + ) { + parent.clipRect(x, y, width, height); + } + + @Override + public final Rectangle getClipBounds() { + return parent.getClipBounds(); + } + + @Override + public final FontMetrics getFontMetrics(Font f) { + return parent.getFontMetrics(f); + } + + @Override + public final void setFont(Font font) { + parent.setFont(font); + } + + @Override + public final Font getFont() { + return parent.getFont(); + } + + @Override + public final void setXORMode(Color c1) { + parent.setXORMode(c1); + } + + @Override + public final void setPaintMode() { + parent.setPaintMode(); + } + + @Override + public final void setColor(Color c) { + parent.setColor(c); + } + + @Override + public final Color getColor() { + return parent.getColor(); + } + + @Override + public final Graphics create() { + return new NOPGraphics2D((Graphics2D)parent.create()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/java2d/ShapeUtils.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,83 @@ +package de.intevation.flys.java2d; + +import java.awt.Shape; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; + +import java.util.HashMap; +import java.util.Map; + +public class ShapeUtils +{ + // TODO: Use enum + public static final int MEASURED = 0; + public static final int DIGITIZED = 1; + public static final int INTERPOLATED = 2; + + public static final boolean DIGITIZED_FILL = false; + public static final boolean MEASURED_FILL = true; + public static final boolean INTERPOLATED_FILL = false; + + public static final Shape DIGITIZED_SHAPE = + createCross(4f); + + public static final Shape MEASURED_SHAPE = + new Rectangle2D.Double(-2, -2, 4, 4); + + public static final Shape INTERPOLATED_SHAPE = + new Ellipse2D.Double(-2, -2, 4, 4); + + protected static Map<Long, Shape> scaledShapesCache = + new HashMap<Long, Shape>(); + + public static final Shape createCross(float size) { + float half = size * 0.5f; + GeneralPath p = new GeneralPath(); + p.moveTo(-half, -half); + p.lineTo(half, half); + p.closePath(); + p.moveTo(-half, half); + p.lineTo(half, -half); + p.closePath(); + return p; + } + + public static Shape scale(Shape shape, float factor) { + if (factor == 1f) { + return shape; + } + AffineTransform xform = + AffineTransform.getScaleInstance(factor, factor); + + GeneralPath gp = new GeneralPath(shape); + return gp.createTransformedShape(xform); + } + + public static synchronized Shape getScaledShape(int type, float size) { + + Long hash = Long.valueOf( + (((long)type) << 32) | Float.floatToIntBits(size)); + + Shape shape = scaledShapesCache.get(hash); + + if (shape == null) { + switch (type) { + case MEASURED: + shape = MEASURED_SHAPE; + break; + case DIGITIZED: + shape = DIGITIZED_SHAPE; + break; + default: + shape = INTERPOLATED_SHAPE; + } + scaledShapesCache.put(hash, shape = scale(shape, size)); + } + + return shape; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/Bounds.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,24 @@ +package de.intevation.flys.jfree; + +import java.io.Serializable; + +import org.jfree.chart.axis.ValueAxis; + + +/** + * Somewhat better Ranges. + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface Bounds extends Serializable { + + Number getLower(); + + Number getUpper(); + + void applyBounds(ValueAxis axis); + + void applyBounds(ValueAxis axis, int percent); + + Bounds combine(Bounds bounds); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,21 @@ +package de.intevation.flys.jfree; + +import java.awt.Shape; + +import org.jfree.chart.entity.XYAnnotationEntity; + +/** + * Chart Entity for Line Labels that should not collide. + */ +public class CollisionFreeLineLabelEntity +extends XYAnnotationEntity { + public CollisionFreeLineLabelEntity( + Shape hotspot, + int rendererIndex, + String toolTip, + String url + ) { + super(hotspot, rendererIndex, toolTip, url); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,146 @@ +package de.intevation.flys.jfree; + +import org.apache.log4j.Logger; + +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.jfree.chart.entity.EntityCollection; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.entity.XYAnnotationEntity; +import org.jfree.chart.plot.PlotRenderingInfo; +import org.jfree.chart.plot.Plot; + +import org.jfree.text.TextUtilities; + +import org.jfree.ui.RectangleEdge; + +/** + * Custom Annotations class that is drawn only if no collisions with other + * already drawn CustomAnnotations in current plot are found. + */ +public class CollisionFreeXYTextAnnotation extends XYTextAnnotation { + + /** Logger for this class. */ + private static Logger logger = + Logger.getLogger(CollisionFreeXYTextAnnotation.class); + + + public CollisionFreeXYTextAnnotation(String text, double x, double y) { + super(text, x, y); + } + + + /** + * Draw the Annotation only if it does not collide with other + * already drawn Annotations- texts. + * + * @param g2 the graphics device. + * @param plot the plot. + * @param dataArea the data area. + * @param domainAxis the domain axis. + * @param rangeAxis the range axis. + * @param rendererIndex the render index. + * @param info state information, escpecially collects info about + * already drawn shapes (and thus annotations), used + * for collision detection. + */ + @Override + public void draw( + java.awt.Graphics2D g2, + XYPlot plot, + java.awt.geom.Rectangle2D dataArea, + ValueAxis domainAxis, + ValueAxis rangeAxis, + int rendererIndex, + PlotRenderingInfo info + ) { + // From superclass, adjusted access only. + PlotOrientation orientation = plot.getOrientation(); + RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( + plot.getDomainAxisLocation(), orientation); + RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( + plot.getRangeAxisLocation(), orientation); + + float anchorX = (float) domainAxis.valueToJava2D( + this.getX(), dataArea, domainEdge); + float anchorY = (float) rangeAxis.valueToJava2D( + this.getY(), dataArea, rangeEdge); + + if (orientation == PlotOrientation.HORIZONTAL) { + float tempAnchor = anchorX; + anchorX = anchorY; + anchorY = tempAnchor; + } + + g2.setFont(getFont()); + Shape hotspot = TextUtilities.calculateRotatedStringBounds( + getText(), g2, anchorX, anchorY, getTextAnchor(), + getRotationAngle(), getRotationAnchor()); + + // Deviation from superclass: prevent collision. + Rectangle2D hotspotBox = hotspot.getBounds2D(); + + if (JFreeUtil.collides(hotspot, info.getOwner().getEntityCollection(), + XYAnnotationEntity.class)) { + return; + } + + if (this.getBackgroundPaint() != null) { + g2.setPaint(this.getBackgroundPaint()); + g2.fill(hotspot); + } + g2.setPaint(getPaint()); + TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY, + getTextAnchor(), getRotationAngle(), getRotationAnchor()); + if (this.isOutlineVisible()) { + g2.setStroke(this.getOutlineStroke()); + g2.setPaint(this.getOutlinePaint()); + g2.draw(hotspot); + } + + //String toolTip = getToolTipText(); + //String url = getURL(); + String toolTip = "CollisionFreeXYTextAnnotation"; + String url = toolTip; + + if (toolTip != null || url != null) { + addEntity(info, hotspot, rendererIndex, toolTip, url); + } + else { + addEntity(info, hotspot, rendererIndex, + "CollisionFreeXYTextAnnotation", + "CollisionFreeXYTextAnnotation"); + } + } + + /** + * A utility method for adding an {@link CollisionFreeXYAnnotationEntity} to + * a {@link PlotRenderingInfo} instance. + * + * @param info the plot rendering info (<code>null</code> permitted). + * @param hotspot the hotspot area. + * @param rendererIndex the renderer index. + * @param toolTipText the tool tip text. + * @param urlText the URL text. + */ + protected void addEntity(PlotRenderingInfo info, + Shape hotspot, int rendererIndex, + String toolTipText, String urlText) { + if (info == null) { + return; + } + EntityCollection entities = info.getOwner().getEntityCollection(); + if (entities == null) { + return; + } + CollisionFreeXYTextAnnotationEntity entity = + new CollisionFreeXYTextAnnotationEntity(hotspot, + rendererIndex, toolTipText, urlText); + entities.add(entity); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotationEntity.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,21 @@ +package de.intevation.flys.jfree; + +import java.awt.Shape; + +import org.jfree.chart.entity.XYAnnotationEntity; + +/** + * Chart Entity for XYTextAnnotations that should not collide. + */ +public class CollisionFreeXYTextAnnotationEntity +extends XYAnnotationEntity { + public CollisionFreeXYTextAnnotationEntity( + Shape hotspot, + int rendererIndex, + String toolTip, + String url + ) { + super(hotspot, rendererIndex, toolTip, url); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/DoubleBounds.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,79 @@ +package de.intevation.flys.jfree; + + +import org.jfree.chart.axis.ValueAxis; +import org.jfree.data.Range; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DoubleBounds implements Bounds { + + protected double lower; + protected double upper; + + + /** + * Default constructor. <b>A DoubleBounds has always set lower < + * upper!</b> + */ + public DoubleBounds(double lower, double upper) { + this.lower = Math.min(lower, upper); + this.upper = Math.max(lower, upper); + } + + + @Override + public Number getLower() { + return Double.valueOf(lower); + } + + + @Override + public Number getUpper() { + return Double.valueOf(upper); + } + + + @Override + public void applyBounds(ValueAxis axis) { + axis.setRange(new Range(lower, upper)); + } + + + /** + * Set extended range to ValueAxis. + * @param percent how many percent to extend (in each direction, + * thus 10 percent on [0,100] -> [-10,110]. + */ + @Override + public void applyBounds(ValueAxis axis, int percent) { + double space = (upper - lower) / 100 * percent; + axis.setRange(new Range(lower-space, upper+space)); + } + + + @Override + public Bounds combine(Bounds bounds) { + if (bounds == null) { + return this; + } + + DoubleBounds other = (DoubleBounds) bounds; + + double otherLower = other.getLower().doubleValue(); + double otherUpper = other.getUpper().doubleValue(); + + return new DoubleBounds( + otherLower < lower ? otherLower : lower, + otherUpper > upper ? otherUpper : upper); + } + + + @Override + public String toString() { + return "DoubleBounds=[" + lower + " ; " + upper + "]"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,576 @@ +package de.intevation.flys.jfree; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.entity.EntityCollection; +import org.jfree.chart.plot.CrosshairState; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.text.TextUtilities; +import org.jfree.ui.RectangleEdge; +import org.jfree.ui.TextAnchor; +import org.jfree.util.BooleanList; +import org.jfree.util.ShapeUtilities; + +/** + * Renderer with additional the additional functionality of renderering minima + * and/or maxima of dataseries contained in datasets. + */ +public class EnhancedLineAndShapeRenderer extends XYLineAndShapeRenderer { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(EnhancedLineAndShapeRenderer.class); + + protected BooleanList isMinimumShapeVisible; + protected BooleanList isMaximumShapeVisible; + protected BooleanList showLineLabel; + + protected Map<Integer, Double> seriesMinimum; + protected Map<Integer, Double> seriesMinimumX; + protected Map<Integer, Double> seriesMaximum; + + protected Map<Integer, Font> lineLabelFonts; + protected Map<Integer, Color> lineLabelTextColors; + protected BooleanList showLineLabelBG; + protected Map<Integer, Color> lineLabelBGColors; + + + public EnhancedLineAndShapeRenderer(boolean lines, boolean shapes) { + super(lines, shapes); + this.isMinimumShapeVisible = new BooleanList(); + this.isMaximumShapeVisible = new BooleanList(); + this.showLineLabel = new BooleanList(); + this.showLineLabelBG = new BooleanList(); + this.seriesMinimum = new HashMap<Integer, Double>(); + this.seriesMaximum = new HashMap<Integer, Double>(); + this.seriesMinimumX = new HashMap<Integer, Double>(); + this.lineLabelFonts = new HashMap<Integer, Font>(); + this.lineLabelTextColors = new HashMap<Integer, Color>(); + this.lineLabelBGColors = new HashMap<Integer, Color>(); + } + + + /** + * Draw a background-box of a text to render. + * @param g2 graphics device to use + * @param text text to draw + * @param textX x-position for text + * @param textY y-position for text + * @param bgColor color to fill box with. + */ + public static void drawTextBox(Graphics2D g2, + String text, float textX, float textY, Color bgColor + ) { + Rectangle2D hotspotBox = g2.getFontMetrics().getStringBounds(text, g2); + float w = (float) hotspotBox.getWidth(), h = (float) hotspotBox.getHeight(); + hotspotBox.setRect(textX, textY-h, w, h); + Color oldColor = g2.getColor(); + g2.setColor(bgColor); + g2.fill(hotspotBox); + g2.setColor(oldColor); + } + + + /** + * Whether or not a specific item in a series (maybe the maxima) should + * be rendered with shape. + */ + public boolean getItemShapeVisible(XYDataset dataset, int series, int item){ + if (super.getItemShapeVisible(series, item)) { + return true; + } + + if (isMinimumShapeVisible(series) && isMinimum(dataset, series, item)) { + return true; + } + + if (isMaximumShapeVisible(series) && isMaximum(dataset, series, item)) { + return true; + } + + return false; + } + + + /** + * Rectangle used to draw maximums shape. + */ + public Shape getMaximumShape(int series, int column) { + return new Rectangle2D.Double(-5d, -5d, 10d, 10d); + } + + + /** + * Rectangle used to draw minimums shape. + */ + public Shape getMinimumShape(int series, int column) { + return new Rectangle2D.Double(-5d, -5d, 10d, 10d); + } + + + /** Get fill paint for the maximum indicators. */ + public Paint getMaximumFillPaint(int series, int column) { + Paint p = getItemPaint(series, column); + + if (p instanceof Color) { + Color c = (Color) p; + Color b = c; + + for (int i = 0; i < 2; i++) { + b = b.darker(); + } + + return b; + } + + logger.warn("Item paint is no instance of Color!"); + return p; + } + + + /** Get fill paint for the minimum indicators. */ + public Paint getMinimumFillPaint(int series, int column) { + Paint p = getItemPaint(series, column); + + if (p instanceof Color) { + Color c = (Color) p; + Color b = c; + + for (int i = 0; i < 2; i++) { + b = b.darker(); + } + + return b; + } + + logger.warn("Item paint is no instance of Color!"); + return p; + } + + + /** + * Overrides XYLineAndShapeRenderer.drawSecondaryPass() to call an adapted + * method getItemShapeVisible() which now takes an XYDataset. So, 99% of + * code equal the code in XYLineAndShapeRenderer. + */ + @Override + protected void drawSecondaryPass( + Graphics2D g2, + XYPlot plot, + XYDataset dataset, + int pass, + int series, + int item, + ValueAxis domainAxis, + Rectangle2D dataArea, + ValueAxis rangeAxis, + CrosshairState crosshairState, + EntityCollection entities + ) { + Shape entityArea = null; + + // get the data point... + double x1 = dataset.getXValue(series, item); + double y1 = dataset.getYValue(series, item); + if (Double.isNaN(y1) || Double.isNaN(x1)) { + return; + } + + PlotOrientation orientation = plot.getOrientation(); + RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); + RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); + double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); + double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); + + if (getItemShapeVisible(dataset, series, item)) { + Shape shape = null; + + // OPTIMIZE: instead of calculating minimum and maximum for every + // point, calculate it just once (assume that dataset + // content does not change during rendering). + // NOTE: Above OPTIMIZE might already be fulfilled to most extend. + boolean isMinimum = isMinimumShapeVisible(series) + && isMinimum(dataset, series, item); + + boolean isMaximum = isMaximumShapeVisible(series) + && isMaximum(dataset, series, item); + + if (isMinimum) { + logger.debug("Create a Minimum shape."); + shape = getMinimumShape(series, item); + } + else if (isMaximum) { + logger.debug("Create a Maximum shape."); + shape = getMaximumShape(series, item); + } + else { + shape = getItemShape(series, item); + } + + if (orientation == PlotOrientation.HORIZONTAL) { + shape = ShapeUtilities.createTranslatedShape(shape, transY1, + transX1); + } + else if (orientation == PlotOrientation.VERTICAL) { + shape = ShapeUtilities.createTranslatedShape(shape, transX1, + transY1); + } + entityArea = shape; + if (shape.intersects(dataArea)) { + if (getItemShapeFilled(series, item)) { + if (getUseFillPaint()) { + g2.setPaint(getItemFillPaint(series, item)); + } + else { + g2.setPaint(getItemPaint(series, item)); + } + g2.fill(shape); + } + if (getDrawOutlines()) { + if (getUseOutlinePaint()) { + g2.setPaint(getItemOutlinePaint(series, item)); + } + else { + g2.setPaint(getItemPaint(series, item)); + } + g2.setStroke(getItemOutlineStroke(series, item)); + g2.draw(shape); + } + + if (isMinimum) { + g2.setPaint(getMinimumFillPaint(series, item)); + g2.fill(shape); + g2.setPaint(getItemOutlinePaint(series, item)); + g2.setStroke(getItemOutlineStroke(series, item)); + g2.draw(shape); + } + else if (isMaximum) { + g2.setPaint(getMaximumFillPaint(series, item)); + g2.fill(shape); + g2.setPaint(getItemOutlinePaint(series, item)); + g2.setStroke(getItemOutlineStroke(series, item)); + g2.draw(shape); + } + } + } // if (getItemShapeVisible(dataset, series, item)) + + double xx = transX1; + double yy = transY1; + if (orientation == PlotOrientation.HORIZONTAL) { + xx = transY1; + yy = transX1; + } + + // Draw the item label if there is one... + if (isItemLabelVisible(series, item)) { + drawItemLabel(g2, orientation, dataset, series, item, xx, yy, + (y1 < 0.0)); + } + + // Draw label of line. + if (dataset instanceof XYSeriesCollection + && isShowLineLabel(series) + && isMinimumX (dataset, series, item) + ) { + XYSeries xYSeries = ((XYSeriesCollection) dataset).getSeries(series); + String waterlevelLabel = (xYSeries instanceof HasLabel) + ? ((HasLabel)xYSeries).getLabel() + : xYSeries.getKey().toString(); + // TODO Force water of some German rivers to flow direction mountains. + + Font oldFont = g2.getFont(); + + Color oldColor = g2.getColor(); + g2.setFont(this.getLineLabelFont(series)); + g2.setColor(this.getLineLabelTextColor(series)); + g2.setBackground(Color.black); + + // Try to always display label if the data is visible. + if (!isPointInRect(dataArea, xx, yy)) { + // Move into the data area. + xx = Math.max(xx, dataArea.getMinX()); + xx = Math.min(xx, dataArea.getMaxX()); + yy = Math.max(yy, dataArea.getMinY()); + yy = Math.min(yy, dataArea.getMaxY()); + } + + // Move to right until no collisions exist anymore + Shape hotspot = TextUtilities.calculateRotatedStringBounds( + waterlevelLabel, g2, (float)xx, (float)yy-3f, + TextAnchor.CENTER_LEFT, + 0f, TextAnchor.CENTER_LEFT); + while (JFreeUtil.collides(hotspot, entities, + CollisionFreeLineLabelEntity.class)) { + xx += 5f; + hotspot = TextUtilities.calculateRotatedStringBounds( + waterlevelLabel, g2, (float)xx, (float)yy-3f, TextAnchor.CENTER_LEFT, + 0f, TextAnchor.CENTER_LEFT); + } + + // Register to avoid collissions. + entities.add(new CollisionFreeLineLabelEntity(hotspot, + 1, "", "")); + + // Fill background. + if (isShowLineLabelBG(series)) { + drawTextBox(g2, waterlevelLabel, (float)xx, (float)yy-3f, + getLineLabelBGColor(series)); + } + + g2.drawString(waterlevelLabel, (float)xx, (float)yy-3f); + + g2.setFont(oldFont); + g2.setColor(oldColor); + } + + int domainAxisIndex = plot.getDomainAxisIndex(domainAxis); + int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis); + updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, + rangeAxisIndex, transX1, transY1, orientation); + + // Add an entity for the item, but only if it falls within the data + // area... + if (entities != null && isPointInRect(dataArea, xx, yy)) { + addEntity(entities, entityArea, dataset, series, item, xx, yy); + } + } + + + /** + * Sets whether or not the minimum should be rendered with shape. + */ + public void setIsMinimumShapeVisisble(int series, boolean isVisible) { + this.isMinimumShapeVisible.setBoolean(series, isVisible); + } + + + /** + * Whether or not the minimum should be rendered with shape. + */ + public boolean isMinimumShapeVisible(int series) { + if (this.isMinimumShapeVisible.size() <= series) { + return false; + } + + return isMinimumShapeVisible.getBoolean(series); + } + + + /** + * Sets whether or not the maximum should be rendered with shape. + */ + public void setIsMaximumShapeVisible(int series, boolean isVisible) { + this.isMaximumShapeVisible.setBoolean(series, isVisible); + } + + + /** + * Whether or not the maximum should be rendered with shape. + */ + public boolean isMaximumShapeVisible(int series) { + if (this.isMaximumShapeVisible.size() <= series) { + return false; + } + + return isMaximumShapeVisible.getBoolean(series); + } + + /** Whether or not a label should be shown for series. */ + public boolean isShowLineLabel(int series) { + if (this.showLineLabel.size() <= series) { + return false; + } + + return showLineLabel.getBoolean(series); + } + + + /** Sets whether or not a label should be shown for series. */ + public void setShowLineLabel(boolean showLineLabel, int series) { + this.showLineLabel.setBoolean(series, showLineLabel); + } + + + /** Whether or not a label should be shown for series. */ + public boolean isShowLineLabelBG(int series) { + if (this.showLineLabelBG.size() <= series) { + return false; + } + + return showLineLabelBG.getBoolean(series); + } + + + public void setShowLineLabelBG(int series, boolean doShow) { + this.showLineLabelBG.setBoolean(series, doShow); + } + + public Color getLineLabelBGColor(int series) { + if (this.lineLabelBGColors.size() <= series) { + return null; + } + + return this.lineLabelBGColors.get(series); + } + + public void setLineLabelBGColor(int series, Color color) { + this.lineLabelBGColors.put(series, color); + } + + public Color getLineLabelTextColor(int series) { + if (this.lineLabelTextColors.size() <= series) { + return null; + } + + return this.lineLabelTextColors.get(series); + } + + public void setLineLabelTextColor(int series, Color color) { + this.lineLabelTextColors.put(series, color); + } + + public void setLineLabelFont(Font font, int series) { + this.lineLabelFonts.put(series, font); + } + + public Font getLineLabelFont(int series) { + return this.lineLabelFonts.get(series); + } + + + /** + * True if the given item of given dataset has the smallest + * X value within this set. + */ + public boolean isMinimumX(XYDataset dataset, int series, int item) { + return dataset.getXValue(series, item) == getMinimumX(dataset, series); + } + + + /** + * Get Minimum X Value of a given series in a dataset. + * The value is stored for later use if queried the first time. + */ + public double getMinimumX(XYDataset dataset, int series) { + Integer key = Integer.valueOf(series); + Double old = seriesMinimumX.get(key); + + if (old != null) { + return old.doubleValue(); + } + + logger.debug("Compute minimum of Series: " + series); + + double min = Double.MAX_VALUE; + + for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { + double tmpValue = dataset.getXValue(series, i); + + if (tmpValue < min) { + min = tmpValue; + } + } + + seriesMinimumX.put(key, Double.valueOf(min)); + + return min; + } + + + /** + * True if the given item of given dataset has the smallest + * Y value within this set. + */ + public boolean isMinimum(XYDataset dataset, int series, int item) { + return dataset.getYValue(series, item) == getMinimum(dataset, series); + } + + + /** + * Get Minimum Y Value of a given series in a dataset. + * The value is stored for later use if queried the first time. + */ + public double getMinimum(XYDataset dataset, int series) { + Integer key = Integer.valueOf(series); + Double old = seriesMinimum.get(key); + + if (old != null) { + return old.doubleValue(); + } + + logger.debug("Compute minimum of Series: " + series); + + double min = Double.MAX_VALUE; + + for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { + double tmpValue = dataset.getYValue(series, i); + + if (tmpValue < min) { + min = tmpValue; + } + } + + seriesMinimum.put(key, Double.valueOf(min)); + + return min; + } + + + /** + * True if the given item of given dataset has the biggest + * Y value within this set. + */ + public boolean isMaximum(XYDataset dataset, int series, int item) { + return dataset.getYValue(series, item) == getMaximum(dataset, series); + } + + + /** + * Get maximum Y Value of a given series in a dataset. + * The value is stored for later use if queried the first time. + */ + public double getMaximum(XYDataset dataset, int series) { + Integer key = Integer.valueOf(series); + Double old = seriesMaximum.get(key); + + if (old != null) { + return old.doubleValue(); + } + + logger.debug("Compute maximum of Series: " + series); + + double max = -Double.MAX_VALUE; + + for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { + double tmpValue = dataset.getYValue(series, i); + + if (tmpValue > max) { + max = tmpValue; + } + } + + seriesMaximum.put(key, Double.valueOf(max)); + + return max; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,107 @@ +package de.intevation.flys.jfree; + +import java.util.Collections; +import java.util.List; + +import org.w3c.dom.Document; + +import org.jfree.chart.annotations.XYTextAnnotation; + +import de.intevation.flys.artifacts.model.HYKFactory; + +/** + * List of Text- Annotations with name and theme. + */ +public class FLYSAnnotation { + + /* 'Other' Text Annotations. */ + protected List<XYTextAnnotation> textAnnotations; + + /** Annotations at axis. */ + protected List<StickyAxisAnnotation> axisTextAnnotations; + + /** Areas at axis. */ + protected List<HYKFactory.Zone> boxes; + + /** Styling information. */ + protected Document theme; + + /** Chart-legend information. */ + protected String label; + + + public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations) { + this(label, annotations, null, null); + } + + + /** Create annotations, parameter might be null. */ + public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations, + List<HYKFactory.Zone> bAnnotations + ) { + this(label, annotations, bAnnotations, null); + } + + + /** Create annotations, parameter might be null. */ + public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations, + List<HYKFactory.Zone> bAnnotations, Document theme + ) { + this.label = label; + this.axisTextAnnotations = (annotations != null) + ? annotations + : Collections.<StickyAxisAnnotation>emptyList(); + this.boxes = (bAnnotations != null) + ? bAnnotations + : Collections.<HYKFactory.Zone>emptyList(); + this.textAnnotations = Collections.<XYTextAnnotation>emptyList(); + this.setTheme(theme); + } + + + public void setLabel(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + public List<StickyAxisAnnotation> getAxisTextAnnotations() { + return axisTextAnnotations; + } + + public void setTextAnnotations(List<XYTextAnnotation> annotations) { + this.textAnnotations = annotations; + } + + /** Set the "other" Text Annotations. */ + public List<XYTextAnnotation> getTextAnnotations() { + return textAnnotations; + } + + public List<HYKFactory.Zone> getBoxes() { + return boxes; + } + + public void setTheme(Document theme) { + this.theme = theme; + } + + public Document getTheme() { + return theme; + } + + /** + * Set sticky axis of all axisTextAnnotations + * to the X axis if it is currently Y, and vice versa. + * @return this + */ + public FLYSAnnotation flipStickyAxis() { + for (StickyAxisAnnotation saa: axisTextAnnotations) { + saa.flipStickyAxis(); + } + return this; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/HasLabel.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,8 @@ +package de.intevation.flys.jfree; + +/** Interface to say something is labelled. */ +public interface HasLabel { + public String getLabel(); + public void setLabel(String label); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/JFreeUtil.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,120 @@ +package de.intevation.flys.jfree; + +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.util.Iterator; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.jfree.chart.entity.ChartEntity; +import org.jfree.chart.entity.EntityCollection; +import org.w3c.dom.Document; + +import de.intevation.flys.artifacts.math.Function; + +public class JFreeUtil { + + private static final Logger logger = Logger.getLogger(JFreeUtil.class); + + /** Do not instantiate. */ + private JFreeUtil() { + } + + + /** + * True if \param hotspot collides with a Entity in \param entities. + * @param hotspot Shape to compare against other shapes (bounds only). + * @param entities entities against which to compare shape. + * @param exclusiveEntityClass If not null, consider only entities of + * given class. + * @return true if a collision (non-zero intersection) exists between + * shapes. + */ + public static boolean collides(Shape hotspot, EntityCollection entities, + Class exclusiveEntityClass) { + if (entities == null) return false; + + Rectangle2D hotspotBox = hotspot.getBounds2D(); + + for (Iterator i = entities.iterator(); i.hasNext(); ) { + Object next = i.next(); + ChartEntity entity = (ChartEntity) next; + if (exclusiveEntityClass == null + || exclusiveEntityClass.isInstance(entity)) + { + if (entity.getArea().intersects(hotspotBox)) { + // Found collision, early stop. + return true; + } + } + } + + return false; + } + + + /** + * This function samples a randomized line that contains of x and y values + * between <i>startX</i>, <i>endX</i>, <i>startY</i> and <i>endY</i>. The + * number of points in the line is specified by <i>num</i>. + * + * @param num The number of points in the line. + * @param startX The min value of the x values. + * @param endX The max value of the x values. + * @param startY The min value of the y values. + * @param endY The max value of the y values. + * @return an array with [allX-values, allY-values]. + * @throws IllegalArgumentException + */ + public static double[][] randomizeLine( + int num, + double startX, + double endX, + double startY, + double endY + ) throws IllegalArgumentException + { + if (num <= 0) { + throw new IllegalArgumentException("Parameter 'num' has to be > 0"); + } + + Random random = new Random(); + + double[] x = new double[num]; + double[] y = new double[num]; + + for (int i = 0; i < num; i++) { + double xFac = random.nextDouble(); + double yFac = random.nextDouble(); + + x[i] = startX + xFac * (endX - startX); + y[i] = startY + yFac * (endY - startY); + + logger.debug("Created new point: " + x[i] + "|" + y[i]); + } + + return new double[][] { x, y }; + } + + + public static StyledXYSeries sampleFunction2D( + Function func, + Document theme, + String seriesKey, + int samples, + double start, + double end + ) { + StyledXYSeries series = new StyledXYSeries(seriesKey, theme); + + double step = (end - start) / (samples - 1); + + for (int i = 0; i < samples; i++) { + double x = start + (step * i); + series.add(x, func.value(x)); + } + + return series; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/ShapeRenderer.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,357 @@ +package de.intevation.flys.jfree; + +/** + * Copyright (c) 2006, 2012 by Intevation GmbH + * + * @author Sascha L. Teichmann (teichmann@intevation.de) + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL coming with FLYS for details. + */ + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.jfree.chart.axis.ValueAxis; + +import org.jfree.chart.labels.ItemLabelPosition; +import org.jfree.chart.labels.XYItemLabelGenerator; + +import org.jfree.chart.plot.CrosshairState; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.PlotRenderingInfo; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.chart.renderer.xy.StandardXYItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRendererState; + +import org.jfree.data.xy.XYDataset; + +import org.jfree.text.TextUtilities; + +import org.jfree.ui.RectangleEdge; + +public class ShapeRenderer +extends StandardXYItemRenderer { + + public static class Entry { + protected Shape shape; + protected Shape frame; + protected Paint paint; + protected boolean filled; + + public Entry( + Shape shape, + Paint paint, + boolean filled + ) { + this.shape = shape; + this.paint = paint; + this.filled = filled; + } + + public Entry( + Shape shape, + Shape frame, + Paint paint, + boolean filled + ) { + this.shape = shape; + this.frame = frame; + this.paint = paint; + this.filled = filled; + } + + public Shape getShape() { + return shape; + } + + public void setShape(Shape shape) { + this.shape = shape; + } + + + public Paint getPaint() { + return paint; + } + + public void setPaint(Paint paint) { + this.paint = paint; + } + + public boolean getFilled() { + return filled; + } + + public void setFilled(boolean filled) { + this.filled = filled; + } + + public boolean equals(Object other) { + Entry entry = (Entry)other; + return filled == entry.filled + && paint.equals(entry.paint) + && shape.equals(entry.shape); + } + + public int hashCode() { + return + shape.hashCode() ^ + paint.hashCode() ^ + (filled ? 1231 : 1237); + } + } // class Entry + + public interface LabelGenerator { + String createLabel(Entry entry); + } // interface EntryLabelGenerator + + protected Entry [] entries; + + protected List<Rectangle2D> labelBoundingBoxes; + + protected Rectangle2D area; + + public ShapeRenderer() { + this(SHAPES); + } + + public ShapeRenderer(int type) { + super(type); + } + + public ShapeRenderer(Map<Entry, Integer> map) { + super(SHAPES); + setEntries(map); + } + + public void setEntries(Entry [] entries) { + this.entries = entries; + } + + public void setEntries(Map<Entry, Integer> map) { + Entry [] entries = new Entry[map.size()]; + + for (Map.Entry<Entry, Integer> entry: map.entrySet()) { + entries[entry.getValue()] = entry.getKey(); + } + + setEntries(entries); + } + + @Override + public Shape getSeriesShape(int series) { + return entries[series].shape; + } + + public Shape getSeriesFrame(int series) { + return entries[series].frame; + } + + @Override + public Paint getSeriesPaint(int series) { + return entries[series].paint; + } + + @Override + public boolean getItemShapeFilled(int series, int item) { + return entries[series].filled; + } + + @Override + public XYItemRendererState initialise( + Graphics2D g2, + Rectangle2D dataArea, + XYPlot plot, + XYDataset data, + PlotRenderingInfo info + ) { + if (labelBoundingBoxes == null) { + labelBoundingBoxes = new ArrayList<Rectangle2D>(32); + } + else { + labelBoundingBoxes.clear(); + } + + area = dataArea; + + return super.initialise(g2, dataArea, plot, data, info); + } + + @Override + public void drawItem( + Graphics2D g2, + XYItemRendererState state, + Rectangle2D dataArea, + PlotRenderingInfo info, + XYPlot plot, + ValueAxis domainAxis, + ValueAxis rangeAxis, + XYDataset dataset, + int series, + int item, + CrosshairState crosshairState, + int pass + ) { + if (!getItemVisible(series, item)) { + return; + } + + // get the data point... + double x1 = dataset.getXValue(series, item); + double y1 = dataset.getYValue(series, item); + if (Double.isNaN(x1) || Double.isNaN(y1)) { + return; + } + + RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); + RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); + double x = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); + double y = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); + + if (dataArea.contains(x, y)) + super.drawItem( + g2, + state, + dataArea, + info, + plot, + domainAxis, + rangeAxis, + dataset, + series, + item, + crosshairState, + pass); + } + + protected Point2D shiftBox(Rectangle2D box) { + + double cx1 = area.getX(); + double cy1 = area.getY(); + double cx2 = cx1 + area.getWidth(); + double cy2 = cy1 + area.getHeight(); + + double bx1 = box.getX(); + double by1 = box.getY(); + double bx2 = bx1 + box.getWidth(); + double by2 = by1 + box.getHeight(); + + double dx; + double dy; + + if (bx1 < cx1) { + dx = cx1 - bx1; + } + else if (bx2 > cx2) { + dx = cx2 - bx2; + } + else { + dx = 0d; + } + + if (by1 < cy1) { + dy = cy1 - by1; + } + else if (by2 > cy2) { + dy = cy2 - by2; + } + else { + dy = 0d; + } + + return new Point2D.Double(dx, dy); + } + + @Override + protected void drawItemLabel( + Graphics2D g2, + PlotOrientation orientation, + XYDataset dataset, + int series, + int item, + double x, + double y, + boolean negative + ) { + XYItemLabelGenerator generator = getItemLabelGenerator(series, item); + if (generator == null) { + return; + } + + Font labelFont = getItemLabelFont(series, item); + + Paint paint = getItemLabelPaint(series, item); + + g2.setFont(labelFont); + g2.setPaint(paint); + + String label = generator.generateLabel(dataset, series, item); + + ATTEMPS: for (int attempt = 0; attempt < 2; ++attempt) { + // get the label position.. + ItemLabelPosition position = null; + + boolean pos; + switch (attempt) { + case 0: pos = negative; break; + case 1: pos = !negative; break; + default: break ATTEMPS; + } + + if (pos) { + position = getNegativeItemLabelPosition(series, item); + } + else { + position = getPositiveItemLabelPosition(series, item); + } + + // work out the label anchor point... + Point2D anchorPoint = calculateLabelAnchorPoint( + position.getItemLabelAnchor(), x, y, orientation); + + Shape labelShape = TextUtilities.calculateRotatedStringBounds( + label, g2, + (float)anchorPoint.getX(), (float)anchorPoint.getY(), + position.getTextAnchor(), position.getAngle(), + position.getRotationAnchor()); + + Rectangle2D bbox = labelShape.getBounds2D(); + + Point2D shift = shiftBox(bbox); + + bbox = new Rectangle2D.Double( + bbox.getX() + shift.getX(), + bbox.getY() + shift.getY(), + bbox.getWidth(), + bbox.getHeight()); + + if (labelBoundingBoxes != null) { + for (Rectangle2D old: labelBoundingBoxes) { + if (old.intersects(bbox)) { + continue ATTEMPS; + } + } + labelBoundingBoxes.add(bbox); + } + + TextUtilities.drawRotatedString( + label, g2, + (float)(anchorPoint.getX() + shift.getX()), + (float)(anchorPoint.getY() + shift.getY()), + position.getTextAnchor(), position.getAngle(), + position.getRotationAnchor()); + break; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,1856 @@ +/* =========================================================== + * JFreeChart : a free chart library for the Java(tm) platform + * =========================================================== + * + * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors. + * + * Project Info: http://www.jfree.org/jfreechart/index.html + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * ------------------------- + * StableXYDifferenceRenderer.java + * ------------------------- + * (C) Copyright 2003-2008, by Object Refinery Limited and Contributors. + * + * Original Author: David Gilbert (for Object Refinery Limited); + * Contributor(s): Richard West, Advanced Micro Devices, Inc. (major rewrite + * of difference drawing algorithm); + * + * Changes: + * -------- + * 30-Apr-2003 : Version 1 (DG); + * 30-Jul-2003 : Modified entity constructor (CZ); + * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG); + * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); + * 09-Feb-2004 : Updated to support horizontal plot orientation (DG); + * 10-Feb-2004 : Added default constructor, setter methods and updated + * Javadocs (DG); + * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); + * 30-Mar-2004 : Fixed bug in getNegativePaint() method (DG); + * 15-Jul-2004 : Switched getX() with getXValue() and getY() with + * getYValue() (DG); + * 25-Aug-2004 : Fixed a bug preventing the use of crosshairs (DG); + * 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG); + * 19-Jan-2005 : Now accesses only primitive values from dataset (DG); + * 22-Feb-2005 : Override getLegendItem(int, int) to return "line" items (DG); + * 13-Apr-2005 : Fixed shape positioning bug (id = 1182062) (DG); + * 20-Apr-2005 : Use generators for legend tooltips and URLs (DG); + * 04-May-2005 : Override equals() method, renamed get/setPlotShapes() --> + * get/setShapesVisible (DG); + * 09-Jun-2005 : Updated equals() to handle GradientPaint (DG); + * 16-Jun-2005 : Fix bug (1221021) affecting stroke used for each series (DG); + * ------------- JFREECHART 1.0.x --------------------------------------------- + * 24-Jan-2007 : Added flag to allow rounding of x-coordinates, and fixed + * bug in clone() (DG); + * 05-Feb-2007 : Added an extra call to updateCrosshairValues() in + * drawItemPass1(), to fix bug 1564967 (DG); + * 06-Feb-2007 : Fixed bug 1086307, crosshairs with multiple axes (DG); + * 08-Mar-2007 : Fixed entity generation (DG); + * 20-Apr-2007 : Updated getLegendItem() for renderer change (DG); + * 23-Apr-2007 : Rewrite of difference drawing algorithm to allow use of + * series with disjoint x-values (RW); + * 04-May-2007 : Set processVisibleItemsOnly flag to false (DG); + * 17-May-2007 : Set datasetIndex and seriesIndex in getLegendItem() (DG); + * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG); + * 05-Nov-2007 : Draw item labels if visible (RW); + * 17-Jun-2008 : Apply legend shape, font and paint attributes (DG); + */ +/* + * For further changes within the FLYS project, refer to the ChangeLog. + */ +package de.intevation.flys.jfree; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Font; +import java.awt.Paint; +import java.awt.geom.Point2D; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.jfree.chart.LegendItem; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.entity.EntityCollection; +import org.jfree.chart.entity.XYItemEntity; +import org.jfree.chart.event.RendererChangeEvent; +import org.jfree.chart.labels.XYToolTipGenerator; +import org.jfree.chart.plot.CrosshairState; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.PlotRenderingInfo; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.urls.XYURLGenerator; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.DefaultXYDataset; +import org.jfree.io.SerialUtilities; +import org.jfree.ui.RectangleEdge; +import org.jfree.util.PaintUtilities; +import org.jfree.util.PublicCloneable; +import org.jfree.util.ShapeUtilities; + +import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRendererState; + +import gnu.trove.TDoubleArrayList; + +import de.intevation.flys.artifacts.math.Linear; + +import java.text.NumberFormat; + +import org.apache.log4j.Logger; + +/** + * A renderer for an {@link XYPlot} that highlights the differences between two + * series. The example shown here is generated by the + * <code>DifferenceChartDemo1.java</code> program included in the JFreeChart + * demo collection: + * <br><br> + * <img src="../../../../../images/StableXYDifferenceRendererSample.png" + * alt="StableXYDifferenceRendererSample.png" /> + */ +public class StableXYDifferenceRenderer extends AbstractXYItemRenderer + implements XYItemRenderer, PublicCloneable { + + private static Logger log = Logger.getLogger(StableXYDifferenceRenderer.class); + + public static final int CALCULATE_POSITIVE_AREA = 1; + public static final int CALCULATE_NEGATIVE_AREA = 2; + public static final int CALCULATE_ALL_AREA = + CALCULATE_POSITIVE_AREA | CALCULATE_NEGATIVE_AREA; + + /** For serialization. */ + private static final long serialVersionUID = -8447915602375584857L; + + /** The paint used to highlight positive differences (y(0) > y(1)). */ + private transient Paint positivePaint; + + /** The paint used to highlight negative differences (y(0) < y(1)). */ + private transient Paint negativePaint; + + /** Display shapes at each point? */ + private boolean shapesVisible; + + /** Display shapes at each point? */ + protected boolean drawOutline; + + /** Which stroke to draw outline with? */ + protected Stroke outlineStroke; + + /** Which paint to draw outline with? */ + protected Paint outlinePaint; + + /** The shape to display in the legend item. */ + private transient Shape legendShape; + + protected boolean drawOriginalSeries; + + /** The color of the label showing the calculated area. */ + protected Color labelColor; + + /** The background color of the label showing the calculated area. */ + protected Color labelBGColor; + + /** Font to draw label of calculated area with. */ + protected Font labelFont; + + /** Template to create i18ned label for area. */ + protected String areaLabelTamplate; + + /** NumberFormat to use for area. */ + protected NumberFormat areaLabelNumberFormat; + + protected int areaCalculationMode; + + protected double positiveArea; + protected double negativeArea; + + /** Whether or not to draw a label in the area. */ + protected boolean labelArea = true; + + + /** Arithmetic centroid of drawn polygons. */ + protected Point2D.Double centroid; + + + /** Number of points that contributed to the centroid. */ + protected int centroidNPoints = 0; + + + /** + * This flag controls whether or not the x-coordinates (in Java2D space) + * are rounded to integers. When set to true, this can avoid the vertical + * striping that anti-aliasing can generate. However, the rounding may not + * be appropriate for output in high resolution formats (for example, + * vector graphics formats such as SVG and PDF). + * + * @since 1.0.4 + */ + private boolean roundXCoordinates; + + /** + * Creates a new renderer with default attributes. + */ + public StableXYDifferenceRenderer() { + this(Color.green, Color.red, false /*, null */); + } + + public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint, + boolean shapes) { + this(positivePaint, negativePaint, shapes, CALCULATE_ALL_AREA); + } + + /** + * Creates a new renderer. + * + * @param positivePaint the highlight color for positive differences + * (<code>null</code> not permitted). + * @param negativePaint the highlight color for negative differences + * (<code>null</code> not permitted). + * @param shapes draw shapes? + */ + public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint, + boolean shapes, int areaCalculationMode) { + if (positivePaint == null) { + throw new IllegalArgumentException( + "Null 'positivePaint' argument."); + } + if (negativePaint == null) { + throw new IllegalArgumentException( + "Null 'negativePaint' argument."); + } + this.positivePaint = positivePaint; + this.negativePaint = negativePaint; + this.shapesVisible = shapes; + this.legendShape = new Rectangle2D.Double(-3.0, -3.0, 10.0, 10.0); + this.roundXCoordinates = false; + this.drawOutline = true; + this.outlineStroke = new BasicStroke(1); + this.outlinePaint = Color.black; + this.drawOriginalSeries = false; + this.areaCalculationMode = areaCalculationMode; + this.labelBGColor = null; + this.centroid = new Point2D.Double(0,0); + } + + public int getAreaCalculationMode() { + return areaCalculationMode; + } + + public void setAreaCalculationMode(int areaCalculationMode) { + this.areaCalculationMode = areaCalculationMode; + } + + + /** Set template to use to create area label (e.g. 'Area=%dm2'). */ + public void setAreaLabelTemplate(String areaTemplate) { + this.areaLabelTamplate = areaTemplate; + } + + + public void setAreaLabelNumberFormat(NumberFormat nf) { + this.areaLabelNumberFormat = nf; + } + + + public boolean isLabelArea() { + return this.labelArea; + } + + public void setLabelArea(boolean label) { + this.labelArea = label; + } + + + /** Set font to paint label with. */ + public void setLabelFont(Font font) { + this.labelFont = font; + } + + + /** Get font with which label is painted. */ + public Font getLabelFont() { + return this.labelFont; + } + + + /** Set color with which to paint label. */ + public void setLabelColor(Color color) { + this.labelColor = color; + } + + + /** Get color with which label is painted. */ + public Color getLabelColor() { + return this.labelColor; + } + + + /** Set color with which to paint label bg. */ + public void setLabelBGColor(Color color) { + this.labelBGColor = color; + } + + + /** Get color with which label is painted. */ + public Color getLabelBGColor() { + return this.labelBGColor; + } + + + public double getCalculatedArea() { + return positiveArea + negativeArea; + } + + /** + * Sets color that is used if drawOutline is true. + */ + public void setOutlinePaint(Paint outlinePaint) { + this.outlinePaint = outlinePaint; + } + + + /** + * Gets color which is used if drawOutline is true. + */ + public Paint getOutlinePaint() { + return this.outlinePaint; + } + + + /** + * Sets Stroke that is used if drawOutline is true. + */ + public void setOutlineStroke(Stroke stroke) { + this.outlineStroke = stroke; + } + + + /** + * Returns Stroke that is used if drawOutline is true. + */ + public Stroke getOutlineStroke() { + return this.outlineStroke; + } + + + /** + * Whether or not to draw the 'Shape' of the area (in contrast to + * shapes at data items). + */ + public void setDrawOutline(boolean doDrawOutline) { + this.drawOutline = doDrawOutline; + } + + + /** + * Returns whether or not to draw the shape of the outline. + */ + public boolean getDrawOutline() { + return this.drawOutline; + } + + + /** + * Returns the paint used to highlight positive differences. + * + * @return The paint (never <code>null</code>). + * + * @see #setPositivePaint(Paint) + */ + public Paint getPositivePaint() { + return this.positivePaint; + } + + /** + * Sets the paint used to highlight positive differences and sends a + * {@link RendererChangeEvent} to all registered listeners. + * + * @param paint the paint (<code>null</code> not permitted). + * + * @see #getPositivePaint() + */ + public void setPositivePaint(Paint paint) { + if (paint == null) { + throw new IllegalArgumentException("Null 'paint' argument."); + } + this.positivePaint = paint; + fireChangeEvent(); + } + + /** + * Returns the paint used to highlight negative differences. + * + * @return The paint (never <code>null</code>). + * + * @see #setNegativePaint(Paint) + */ + public Paint getNegativePaint() { + return this.negativePaint; + } + + /** + * Sets the paint used to highlight negative differences. + * + * @param paint the paint (<code>null</code> not permitted). + * + * @see #getNegativePaint() + */ + public void setNegativePaint(Paint paint) { + if (paint == null) { + throw new IllegalArgumentException("Null 'paint' argument."); + } + this.negativePaint = paint; + notifyListeners(new RendererChangeEvent(this)); + } + + /** + * Returns a flag that controls whether or not shapes are drawn for each + * data value. + * + * @return A boolean. + * + * @see #setShapesVisible(boolean) + */ + public boolean getShapesVisible() { + return this.shapesVisible; + } + + /** + * Sets a flag that controls whether or not shapes are drawn for each + * data value, and sends a {@link RendererChangeEvent} to all registered + * listeners. + * + * @param flag the flag. + * + * @see #getShapesVisible() + */ + public void setShapesVisible(boolean flag) { + this.shapesVisible = flag; + fireChangeEvent(); + } + + /** + * Returns the shape used to represent a line in the legend. + * + * @return The legend line (never <code>null</code>). + * + * @see #setLegendLine(Shape) + */ + public Shape getLegendLine() { + return this.legendShape; + } + + /** + * Sets the shape used as a line in each legend item and sends a + * {@link RendererChangeEvent} to all registered listeners. + * + * @param line the line (<code>null</code> not permitted). + * + * @see #getLegendLine() + */ + public void setLegendLine(Shape line) { + if (line == null) { + throw new IllegalArgumentException("Null 'line' argument."); + } + this.legendShape = line; + fireChangeEvent(); + } + + /** + * Returns the flag that controls whether or not the x-coordinates (in + * Java2D space) are rounded to integer values. + * + * @return The flag. + * + * @since 1.0.4 + * + * @see #setRoundXCoordinates(boolean) + */ + public boolean getRoundXCoordinates() { + return this.roundXCoordinates; + } + + /** + * Sets the flag that controls whether or not the x-coordinates (in + * Java2D space) are rounded to integer values, and sends a + * {@link RendererChangeEvent} to all registered listeners. + * + * @param round the new flag value. + * + * @since 1.0.4 + * + * @see #getRoundXCoordinates() + */ + public void setRoundXCoordinates(boolean round) { + this.roundXCoordinates = round; + fireChangeEvent(); + } + + /** + * Initialises the renderer and returns a state object that should be + * passed to subsequent calls to the drawItem() method. This method will + * be called before the first item is rendered, giving the renderer an + * opportunity to initialise any state information it wants to maintain. + * The renderer can do nothing if it chooses. + * + * @param g2 the graphics device. + * @param dataArea the (visible) area inside the axes. + * @param plot the plot. + * @param data the data. + * @param info an optional info collection object to return data back to + * the caller. + * + * @return A state object. + */ + public XYItemRendererState initialise(Graphics2D g2, + Rectangle2D dataArea, + XYPlot plot, + XYDataset data, + PlotRenderingInfo info) { + + XYItemRendererState state = super.initialise(g2, dataArea, plot, data, + info); + state.setProcessVisibleItemsOnly(false); + return state; + } + + /** + * Returns <code>2</code>, the number of passes required by the renderer. + * The {@link XYPlot} will run through the dataset this number of times. + * + * @return The number of passes required by the renderer. + */ + public int getPassCount() { + return 2; + } + + + /** + * Adds x/y data to series. + */ + private static final void addSeries( + DefaultXYDataset ds, + Comparable key, + TDoubleArrayList xs, + TDoubleArrayList ys + ) { + ds.addSeries( + key, + new double [][] { + xs.toNativeArray(), + ys.toNativeArray() + }); + } + + protected static List<XYDataset> splitByNaNsOneSeries( + XYDataset dataset + ) { + List<XYDataset> datasets = new ArrayList<XYDataset>(); + + int N = dataset.getItemCount(0); + TDoubleArrayList xs = new TDoubleArrayList(N); + TDoubleArrayList ys = new TDoubleArrayList(N); + for (int i = 0; i < N; ++i) { + double x = dataset.getXValue(0, i); + double y = dataset.getYValue(0, i); + if (Double.isNaN(x) || Double.isNaN(y)) { + if (!xs.isEmpty()) { + DefaultXYDataset ds = new DefaultXYDataset(); + addSeries(ds, dataset.getSeriesKey(0), xs, ys); + datasets.add(ds); + xs.resetQuick(); + ys.resetQuick(); + } + } + else { + xs.add(x); + ys.add(y); + } + } + if (!xs.isEmpty()) { + DefaultXYDataset ds = new DefaultXYDataset(); + addSeries(ds, dataset.getSeriesKey(0), xs, ys); + datasets.add(ds); + } + + return datasets; + } + + private static final boolean add(TDoubleArrayList xs, double x) { + int N = xs.size(); + if (N == 0 || xs.getQuick(N-1) < x) { + xs.add(x); + return true; + } + log.debug("pushed smaller"); + return false; + } + + protected static List<XYDataset> splitByNaNsTwoSeries( + XYDataset dataset + ) { + boolean debug = log.isDebugEnabled(); + + List<XYDataset> datasets = new ArrayList<XYDataset>(); + + int N = dataset.getItemCount(0); + int M = dataset.getItemCount(1); + + int i = 0, j = 0; + // ignore leading NaNs + for (; i < N; ++i) { + double x = dataset.getXValue(0, i); + double y = dataset.getYValue(0, i); + if (!Double.isNaN(x) && !Double.isNaN(y)) { + break; + } + } + + for (; j < M; ++j) { + double x = dataset.getXValue(1, j); + double y = dataset.getYValue(1, j); + if (!Double.isNaN(x) && !Double.isNaN(y)) { + break; + } + } + + TDoubleArrayList six = new TDoubleArrayList(); + TDoubleArrayList siy = new TDoubleArrayList(); + TDoubleArrayList sjx = new TDoubleArrayList(); + TDoubleArrayList sjy = new TDoubleArrayList(); + + while (i < N && j < M) { + int ni = i+1; + for (; ni < N && !Double.isNaN(dataset.getXValue(0, ni)); ++ni); + for (; ni < N && Double.isNaN(dataset.getXValue(0, ni)); ++ni); + + int nj = j+1; + for (; nj < M && !Double.isNaN(dataset.getXValue(1, nj)); ++nj); + for (; nj < M && Double.isNaN(dataset.getXValue(1, nj)); ++nj); + + if (ni == N && nj == M) { // no more splits + log.debug("no more splits ...."); + for (; i < ni; ++i) { + double x = dataset.getXValue(0, i); + double y = dataset.getYValue(0, i); + if (!Double.isNaN(x) + && !Double.isNaN(y) + && add(six, x)) { + siy.add(y); + } + } + for (; j < nj; ++j) { + double x = dataset.getXValue(1, j); + double y = dataset.getYValue(1, j); + if (!Double.isNaN(x) + && !Double.isNaN(y) + && add(sjx, x)) { + sjy.add(y); + } + } + if (!six.isEmpty() && !sjx.isEmpty()) { + DefaultXYDataset ds = new DefaultXYDataset(); + addSeries(ds, dataset.getSeriesKey(0), six, siy); + addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); + datasets.add(ds); + } + break; + } + + if (debug) { + log.debug("ni: " + ni + " " + N); + log.debug("nj: " + nj + " " + M); + } + + double xni = ni < N + ? dataset.getXValue(0, ni) + : Double.MAX_VALUE; + + double xnj = nj < M + ? dataset.getXValue(1, nj) + : Double.MAX_VALUE; + + double xns = Math.min(xni, xnj); + + double pushxi = Double.NaN; + double pushyi = Double.NaN; + double pushxj = Double.NaN; + double pushyj = Double.NaN; + + for (; i < ni; ++i) { + double x = dataset.getXValue(0, i); + double y = dataset.getYValue(0, i); + if (Double.isNaN(x) || Double.isNaN(y)) { + continue; + } + if (x < xns) { + if (add(six, x)) { + siy.add(y); + } + continue; + } + if (x == xns) { // exact match + if (add(six, x)) { + siy.add(y); + } + pushxi = x; pushyi = y; + } + else { // x > xns: intersection + if (debug) { + log.debug("xns: " + xns); + log.debug("x/y: " + x + " / " + y); + } + int SIX = six.size(); + if (SIX > 0) { // should always be true + double yns = Linear.linear( + xns, + six.getQuick(SIX-1), x, + siy.getQuick(SIX-1), y); + if (debug) { + log.debug("intersection at: " + yns); + } + if (add(six, xns)) { + siy.add(yns); + } + pushxi = xns; + pushyi = yns; + } + } + break; // Split point reached. + } + + for (; j < nj; ++j) { + double x = dataset.getXValue(1, j); + double y = dataset.getYValue(1, j); + if (Double.isNaN(x) || Double.isNaN(y)) { + continue; + } + if (x < xns) { + if (add(sjx, x)) { + sjy.add(y); + } + continue; + } + if (x == xns) { // exact match + if (add(sjx, x)) { + sjy.add(y); + } + pushxj = x; pushyj = y; + } + else { // x > xns: intersection + int SJX = sjx.size(); + if (SJX > 0) { // should always be true + double yns = Linear.linear( + xns, + sjx.getQuick(SJX-1), x, + sjy.getQuick(SJX-1), y); + if (debug) { + log.debug("intersection at: " + yns); + } + if (add(sjx, xns)) { + sjy.add(yns); + } + pushxj = xns; pushyj = yns; + } + } + break; // Split point reached. + } + + if (!six.isEmpty() && !sjx.isEmpty()) { + DefaultXYDataset ds = new DefaultXYDataset(); + addSeries(ds, dataset.getSeriesKey(0), six, siy); + addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); + datasets.add(ds); + } + + six.resetQuick(); siy.resetQuick(); + sjx.resetQuick(); sjy.resetQuick(); + + // Push split points. + if (!Double.isNaN(pushxi)) { + six.add(pushxi); + siy.add(pushyi); + } + + if (!Double.isNaN(pushxj)) { + sjx.add(pushxj); + sjy.add(pushyj); + } + } + + // Copy the rest. + for (; i < N; ++i) { + double x = dataset.getXValue(0, i); + double y = dataset.getXValue(0, i); + if (!Double.isNaN(x) + && !Double.isNaN(y) + && add(six, x)) { + siy.add(y); + } + } + + for (; j < M; ++j) { + double x = dataset.getXValue(1, j); + double y = dataset.getXValue(1, j); + if (!Double.isNaN(x) + && !Double.isNaN(y) + && add(sjx, x)) { + sjy.add(y); + } + } + + // Build final dataset. + if (!six.isEmpty() && !sjx.isEmpty()) { + DefaultXYDataset ds = new DefaultXYDataset(); + addSeries(ds, dataset.getSeriesKey(0), six, siy); + addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); + datasets.add(ds); + } + + if (debug) { + log.debug("datasets after split: " + datasets.size()); + } + + return datasets; + } + + public static List<XYDataset> splitByNaNs(XYDataset dataset) { + + switch (dataset.getSeriesCount()) { + case 0: + return Collections.<XYDataset>emptyList(); + case 1: + return splitByNaNsOneSeries(dataset); + default: // two or more + return splitByNaNsTwoSeries(dataset); + } + } + + + /** + * Draws the visual representation of a single data item. + * + * @param g2 the graphics device. + * @param state the renderer state. + * @param dataArea the area within which the data is being drawn. + * @param info collects information about the drawing. + * @param plot the plot (can be used to obtain standard color + * information etc). + * @param domainAxis the domain (horizontal) axis. + * @param rangeAxis the range (vertical) axis. + * @param dataset the dataset. + * @param series the series index (zero-based). + * @param item the item index (zero-based). + * @param crosshairState crosshair information for the plot + * (<code>null</code> permitted). + * @param pass the pass index. + */ + public void drawItem(Graphics2D g2, + XYItemRendererState state, + Rectangle2D dataArea, + PlotRenderingInfo info, + XYPlot plot, + ValueAxis domainAxis, + ValueAxis rangeAxis, + XYDataset dataset, + int series, + int item, + CrosshairState crosshairState, + int pass) { + switch (pass) { + case 0: + for (XYDataset ds: splitByNaNs(dataset)) { + drawItemPass0(g2, dataArea, info, + plot, domainAxis, rangeAxis, + ds, series, item, crosshairState); + } + break; + case 1: + drawItemPass1(g2, dataArea, info, + plot, domainAxis, rangeAxis, + dataset, series, item, crosshairState); + } + + // Find geometric middle, calculate area and paint a string with it here. + if (pass == 1 && this.labelArea && areaLabelNumberFormat != null && areaLabelTamplate != null) { + double center_x = centroid.getX(); + double center_y = centroid.getY(); + center_x = domainAxis.valueToJava2D(center_x, dataArea, + plot.getDomainAxisEdge()); + center_y = rangeAxis.valueToJava2D(center_y, dataArea, + plot.getRangeAxisEdge()); + + // Respect text-extend if text should appear really centered. + + float area = 0f; + if (areaCalculationMode == CALCULATE_POSITIVE_AREA + || areaCalculationMode == CALCULATE_ALL_AREA) { + area += Math.abs(positiveArea); + } + if (areaCalculationMode == CALCULATE_NEGATIVE_AREA + || areaCalculationMode == CALCULATE_ALL_AREA) { + area += Math.abs(negativeArea); + } + if (area != 0f) { + Color oldColor = g2.getColor(); + Font oldFont = g2.getFont(); + g2.setFont(labelFont); + String labelText = String.format(this.areaLabelTamplate, + areaLabelNumberFormat.format(area)); + if (labelBGColor != null) { + EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText, + (float)center_x, (float)center_y, labelBGColor); + } + g2.setColor(labelColor); + g2.drawString(labelText, (float)center_x, (float)center_y); + g2.setFont(oldFont); + g2.setColor(oldColor); + } + } + } + + /** + * Draws the visual representation of a single data item, first pass. + * + * @param x_graphics the graphics device. + * @param x_dataArea the area within which the data is being drawn. + * @param x_info collects information about the drawing. + * @param x_plot the plot (can be used to obtain standard color + * information etc). + * @param x_domainAxis the domain (horizontal) axis. + * @param x_rangeAxis the range (vertical) axis. + * @param x_dataset the dataset. + * @param x_series the series index (zero-based). + * @param x_item the item index (zero-based). + * @param x_crosshairState crosshair information for the plot + * (<code>null</code> permitted). + */ + protected void drawItemPass0(Graphics2D x_graphics, + Rectangle2D x_dataArea, + PlotRenderingInfo x_info, + XYPlot x_plot, + ValueAxis x_domainAxis, + ValueAxis x_rangeAxis, + XYDataset x_dataset, + int x_series, + int x_item, + CrosshairState x_crosshairState) { + + if (!((0 == x_series) && (0 == x_item))) { + return; + } + + boolean b_impliedZeroSubtrahend = (1 == x_dataset.getSeriesCount()); + + // check if either series is a degenerate case (i.e. less than 2 points) + if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend)) { + return; + } + + // check if series are disjoint (i.e. domain-spans do not overlap) + if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset)) { + return; + } + + // polygon definitions + LinkedList l_minuendXs = new LinkedList(); + LinkedList l_minuendYs = new LinkedList(); + LinkedList l_subtrahendXs = new LinkedList(); + LinkedList l_subtrahendYs = new LinkedList(); + LinkedList l_polygonXs = new LinkedList(); + LinkedList l_polygonYs = new LinkedList(); + + // state + int l_minuendItem = 0; + int l_minuendItemCount = x_dataset.getItemCount(0); + Double l_minuendCurX = null; + Double l_minuendNextX = null; + Double l_minuendCurY = null; + Double l_minuendNextY = null; + double l_minuendMaxY = Double.NEGATIVE_INFINITY; + double l_minuendMinY = Double.POSITIVE_INFINITY; + + int l_subtrahendItem = 0; + int l_subtrahendItemCount = 0; // actual value set below + Double l_subtrahendCurX = null; + Double l_subtrahendNextX = null; + Double l_subtrahendCurY = null; + Double l_subtrahendNextY = null; + double l_subtrahendMaxY = Double.NEGATIVE_INFINITY; + double l_subtrahendMinY = Double.POSITIVE_INFINITY; + + // if a subtrahend is not specified, assume it is zero + if (b_impliedZeroSubtrahend) { + l_subtrahendItem = 0; + l_subtrahendItemCount = 2; + l_subtrahendCurX = new Double(x_dataset.getXValue(0, 0)); + l_subtrahendNextX = new Double(x_dataset.getXValue(0, + (l_minuendItemCount - 1))); + l_subtrahendCurY = new Double(0.0); + l_subtrahendNextY = new Double(0.0); + l_subtrahendMaxY = 0.0; + l_subtrahendMinY = 0.0; + + l_subtrahendXs.add(l_subtrahendCurX); + l_subtrahendYs.add(l_subtrahendCurY); + } + else { + l_subtrahendItemCount = x_dataset.getItemCount(1); + } + + boolean b_minuendDone = false; + boolean b_minuendAdvanced = true; + boolean b_minuendAtIntersect = false; + boolean b_minuendFastForward = false; + boolean b_subtrahendDone = false; + boolean b_subtrahendAdvanced = true; + boolean b_subtrahendAtIntersect = false; + boolean b_subtrahendFastForward = false; + boolean b_colinear = false; + + boolean b_positive; + + // coordinate pairs + double l_x1 = 0.0, l_y1 = 0.0; // current minuend point + double l_x2 = 0.0, l_y2 = 0.0; // next minuend point + double l_x3 = 0.0, l_y3 = 0.0; // current subtrahend point + double l_x4 = 0.0, l_y4 = 0.0; // next subtrahend point + + // fast-forward through leading tails + boolean b_fastForwardDone = false; + while (!b_fastForwardDone) { + // get the x and y coordinates + l_x1 = x_dataset.getXValue(0, l_minuendItem); + l_y1 = x_dataset.getYValue(0, l_minuendItem); + l_x2 = x_dataset.getXValue(0, l_minuendItem + 1); + l_y2 = x_dataset.getYValue(0, l_minuendItem + 1); + + l_minuendCurX = new Double(l_x1); + l_minuendCurY = new Double(l_y1); + l_minuendNextX = new Double(l_x2); + l_minuendNextY = new Double(l_y2); + + if (b_impliedZeroSubtrahend) { + l_x3 = l_subtrahendCurX.doubleValue(); + l_y3 = l_subtrahendCurY.doubleValue(); + l_x4 = l_subtrahendNextX.doubleValue(); + l_y4 = l_subtrahendNextY.doubleValue(); + } + else { + l_x3 = x_dataset.getXValue(1, l_subtrahendItem); + l_y3 = x_dataset.getYValue(1, l_subtrahendItem); + l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1); + l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1); + + l_subtrahendCurX = new Double(l_x3); + l_subtrahendCurY = new Double(l_y3); + l_subtrahendNextX = new Double(l_x4); + l_subtrahendNextY = new Double(l_y4); + } + + if (l_x2 <= l_x3) { + // minuend needs to be fast forwarded + l_minuendItem++; + b_minuendFastForward = true; + continue; + } + + if (l_x4 <= l_x1) { + // subtrahend needs to be fast forwarded + l_subtrahendItem++; + b_subtrahendFastForward = true; + continue; + } + + // check if initial polygon needs to be clipped + if ((l_x3 < l_x1) && (l_x1 < l_x4)) { + // project onto subtrahend + double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); + l_subtrahendCurX = l_minuendCurX; + l_subtrahendCurY = new Double((l_slope * l_x1) + + (l_y3 - (l_slope * l_x3))); + + l_subtrahendXs.add(l_subtrahendCurX); + l_subtrahendYs.add(l_subtrahendCurY); + } + + if ((l_x1 < l_x3) && (l_x3 < l_x2)) { + // project onto minuend + double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); + l_minuendCurX = l_subtrahendCurX; + l_minuendCurY = new Double((l_slope * l_x3) + + (l_y1 - (l_slope * l_x1))); + + l_minuendXs.add(l_minuendCurX); + l_minuendYs.add(l_minuendCurY); + } + + l_minuendMaxY = l_minuendCurY.doubleValue(); + l_minuendMinY = l_minuendCurY.doubleValue(); + l_subtrahendMaxY = l_subtrahendCurY.doubleValue(); + l_subtrahendMinY = l_subtrahendCurY.doubleValue(); + + b_fastForwardDone = true; + } + + // start of algorithm + while (!b_minuendDone && !b_subtrahendDone) { + if (!b_minuendDone && !b_minuendFastForward && b_minuendAdvanced) { + l_x1 = x_dataset.getXValue(0, l_minuendItem); + l_y1 = x_dataset.getYValue(0, l_minuendItem); + l_minuendCurX = new Double(l_x1); + l_minuendCurY = new Double(l_y1); + + if (!b_minuendAtIntersect) { + l_minuendXs.add(l_minuendCurX); + l_minuendYs.add(l_minuendCurY); + } + + l_minuendMaxY = Math.max(l_minuendMaxY, l_y1); + l_minuendMinY = Math.min(l_minuendMinY, l_y1); + + l_x2 = x_dataset.getXValue(0, l_minuendItem + 1); + l_y2 = x_dataset.getYValue(0, l_minuendItem + 1); + l_minuendNextX = new Double(l_x2); + l_minuendNextY = new Double(l_y2); + } + + // never updated the subtrahend if it is implied to be zero + if (!b_impliedZeroSubtrahend && !b_subtrahendDone + && !b_subtrahendFastForward && b_subtrahendAdvanced) { + l_x3 = x_dataset.getXValue(1, l_subtrahendItem); + l_y3 = x_dataset.getYValue(1, l_subtrahendItem); + l_subtrahendCurX = new Double(l_x3); + l_subtrahendCurY = new Double(l_y3); + + if (!b_subtrahendAtIntersect) { + l_subtrahendXs.add(l_subtrahendCurX); + l_subtrahendYs.add(l_subtrahendCurY); + } + + l_subtrahendMaxY = Math.max(l_subtrahendMaxY, l_y3); + l_subtrahendMinY = Math.min(l_subtrahendMinY, l_y3); + + l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1); + l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1); + l_subtrahendNextX = new Double(l_x4); + l_subtrahendNextY = new Double(l_y4); + } + + // deassert b_*FastForward (only matters for 1st time through loop) + b_minuendFastForward = false; + b_subtrahendFastForward = false; + + Double l_intersectX = null; + Double l_intersectY = null; + boolean b_intersect = false; + + b_minuendAtIntersect = false; + b_subtrahendAtIntersect = false; + + // check for intersect + if ((l_x2 == l_x4) && (l_y2 == l_y4)) { + // check if line segments are colinear + if ((l_x1 == l_x3) && (l_y1 == l_y3)) { + b_colinear = true; + } + else { + // the intersect is at the next point for both the minuend + // and subtrahend + l_intersectX = new Double(l_x2); + l_intersectY = new Double(l_y2); + + b_intersect = true; + b_minuendAtIntersect = true; + b_subtrahendAtIntersect = true; + } + } + else { + // compute common denominator + double l_denominator = ((l_y4 - l_y3) * (l_x2 - l_x1)) + - ((l_x4 - l_x3) * (l_y2 - l_y1)); + + // compute common deltas + double l_deltaY = l_y1 - l_y3; + double l_deltaX = l_x1 - l_x3; + + // compute numerators + double l_numeratorA = ((l_x4 - l_x3) * l_deltaY) + - ((l_y4 - l_y3) * l_deltaX); + double l_numeratorB = ((l_x2 - l_x1) * l_deltaY) + - ((l_y2 - l_y1) * l_deltaX); + + // check if line segments are colinear + if ((0 == l_numeratorA) && (0 == l_numeratorB) + && (0 == l_denominator)) { + b_colinear = true; + } + else { + // check if previously colinear + if (b_colinear) { + // clear colinear points and flag + l_minuendXs.clear(); + l_minuendYs.clear(); + l_subtrahendXs.clear(); + l_subtrahendYs.clear(); + l_polygonXs.clear(); + l_polygonYs.clear(); + + b_colinear = false; + + // set new starting point for the polygon + boolean b_useMinuend = ((l_x3 <= l_x1) + && (l_x1 <= l_x4)); + l_polygonXs.add(b_useMinuend ? l_minuendCurX + : l_subtrahendCurX); + l_polygonYs.add(b_useMinuend ? l_minuendCurY + : l_subtrahendCurY); + } + + // compute slope components + double l_slopeA = l_numeratorA / l_denominator; + double l_slopeB = l_numeratorB / l_denominator; + + // check if the line segments intersect + if ((0 < l_slopeA) && (l_slopeA <= 1) && (0 < l_slopeB) + && (l_slopeB <= 1)) { + // compute the point of intersection + double l_xi = l_x1 + (l_slopeA * (l_x2 - l_x1)); + double l_yi = l_y1 + (l_slopeA * (l_y2 - l_y1)); + + l_intersectX = new Double(l_xi); + l_intersectY = new Double(l_yi); + b_intersect = true; + b_minuendAtIntersect = ((l_xi == l_x2) + && (l_yi == l_y2)); + b_subtrahendAtIntersect = ((l_xi == l_x4) + && (l_yi == l_y4)); + + // advance minuend and subtrahend to intesect + l_minuendCurX = l_intersectX; + l_minuendCurY = l_intersectY; + l_subtrahendCurX = l_intersectX; + l_subtrahendCurY = l_intersectY; + } + } + } + + if (b_intersect) { + // create the polygon + // add the minuend's points to polygon + l_polygonXs.addAll(l_minuendXs); + l_polygonYs.addAll(l_minuendYs); + + // add intersection point to the polygon + l_polygonXs.add(l_intersectX); + l_polygonYs.add(l_intersectY); + + // add the subtrahend's points to the polygon in reverse + Collections.reverse(l_subtrahendXs); + Collections.reverse(l_subtrahendYs); + l_polygonXs.addAll(l_subtrahendXs); + l_polygonYs.addAll(l_subtrahendYs); + + // create an actual polygon + b_positive = (l_subtrahendMaxY <= l_minuendMaxY) + && (l_subtrahendMinY <= l_minuendMinY); + createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, + x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); + + // clear the point vectors + l_minuendXs.clear(); + l_minuendYs.clear(); + l_subtrahendXs.clear(); + l_subtrahendYs.clear(); + l_polygonXs.clear(); + l_polygonYs.clear(); + + // set the maxY and minY values to intersect y-value + double l_y = l_intersectY.doubleValue(); + l_minuendMaxY = l_y; + l_subtrahendMaxY = l_y; + l_minuendMinY = l_y; + l_subtrahendMinY = l_y; + + // add interection point to new polygon + l_polygonXs.add(l_intersectX); + l_polygonYs.add(l_intersectY); + } + + // advance the minuend if needed + if (l_x2 <= l_x4) { + l_minuendItem++; + b_minuendAdvanced = true; + } + else { + b_minuendAdvanced = false; + } + + // advance the subtrahend if needed + if (l_x4 <= l_x2) { + l_subtrahendItem++; + b_subtrahendAdvanced = true; + } + else { + b_subtrahendAdvanced = false; + } + + b_minuendDone = (l_minuendItem == (l_minuendItemCount - 1)); + b_subtrahendDone = (l_subtrahendItem == (l_subtrahendItemCount + - 1)); + } + + // check if the final polygon needs to be clipped + if (b_minuendDone && (l_x3 < l_x2) && (l_x2 < l_x4)) { + // project onto subtrahend + double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); + l_subtrahendNextX = l_minuendNextX; + l_subtrahendNextY = new Double((l_slope * l_x2) + + (l_y3 - (l_slope * l_x3))); + } + + if (b_subtrahendDone && (l_x1 < l_x4) && (l_x4 < l_x2)) { + // project onto minuend + double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); + l_minuendNextX = l_subtrahendNextX; + l_minuendNextY = new Double((l_slope * l_x4) + + (l_y1 - (l_slope * l_x1))); + } + + // consider last point of minuend and subtrahend for determining + // positivity + l_minuendMaxY = Math.max(l_minuendMaxY, + l_minuendNextY.doubleValue()); + l_subtrahendMaxY = Math.max(l_subtrahendMaxY, + l_subtrahendNextY.doubleValue()); + l_minuendMinY = Math.min(l_minuendMinY, + l_minuendNextY.doubleValue()); + l_subtrahendMinY = Math.min(l_subtrahendMinY, + l_subtrahendNextY.doubleValue()); + + // add the last point of the minuned and subtrahend + l_minuendXs.add(l_minuendNextX); + l_minuendYs.add(l_minuendNextY); + l_subtrahendXs.add(l_subtrahendNextX); + l_subtrahendYs.add(l_subtrahendNextY); + + // create the polygon + // add the minuend's points to polygon + l_polygonXs.addAll(l_minuendXs); + l_polygonYs.addAll(l_minuendYs); + + // add the subtrahend's points to the polygon in reverse + Collections.reverse(l_subtrahendXs); + Collections.reverse(l_subtrahendYs); + l_polygonXs.addAll(l_subtrahendXs); + l_polygonYs.addAll(l_subtrahendYs); + + // create an actual polygon + b_positive = (l_subtrahendMaxY <= l_minuendMaxY) + && (l_subtrahendMinY <= l_minuendMinY); + createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, + x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); + } + + /** + * Draws the visual representation of a single data item, second pass. In + * the second pass, the renderer draws the lines and shapes for the + * individual points in the two series. + * + * @param x_graphics the graphics device. + * @param x_dataArea the area within which the data is being drawn. + * @param x_info collects information about the drawing. + * @param x_plot the plot (can be used to obtain standard color + * information etc). + * @param x_domainAxis the domain (horizontal) axis. + * @param x_rangeAxis the range (vertical) axis. + * @param x_dataset the dataset. + * @param x_series the series index (zero-based). + * @param x_item the item index (zero-based). + * @param x_crosshairState crosshair information for the plot + * (<code>null</code> permitted). + */ + protected void drawItemPass1(Graphics2D x_graphics, + Rectangle2D x_dataArea, + PlotRenderingInfo x_info, + XYPlot x_plot, + ValueAxis x_domainAxis, + ValueAxis x_rangeAxis, + XYDataset x_dataset, + int x_series, + int x_item, + CrosshairState x_crosshairState) { + + Shape l_entityArea = null; + EntityCollection l_entities = null; + if (null != x_info) { + l_entities = x_info.getOwner().getEntityCollection(); + } + + Paint l_seriesPaint = getItemPaint(x_series, x_item); + Stroke l_seriesStroke = getItemStroke(x_series, x_item); + x_graphics.setPaint(l_seriesPaint); + x_graphics.setStroke(l_seriesStroke); + + PlotOrientation l_orientation = x_plot.getOrientation(); + RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); + RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); + + double l_x0 = x_dataset.getXValue(x_series, x_item); + double l_y0 = x_dataset.getYValue(x_series, x_item); + double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, + l_domainAxisLocation); + double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, + l_rangeAxisLocation); + + // These are the shapes of the series items. + if (getShapesVisible()) { + Shape l_shape = getItemShape(x_series, x_item); + if (l_orientation == PlotOrientation.HORIZONTAL) { + l_shape = ShapeUtilities.createTranslatedShape(l_shape, + l_y1, l_x1); + } + else { + l_shape = ShapeUtilities.createTranslatedShape(l_shape, + l_x1, l_y1); + } + if (l_shape.intersects(x_dataArea)) { + x_graphics.setPaint(getItemPaint(x_series, x_item)); + x_graphics.fill(l_shape); + /* TODO We could draw the shapes of single items here. + if (drawOutline) { + x_graphics.setPaint(this.outlinePaint); + x_graphics.setStroke(this.outlineStroke); + x_graphics.draw(l_shape); + } + */ + } + l_entityArea = l_shape; + } // if (getShapesVisible()) + + // add an entity for the item... + if (null != l_entities) { + if (null == l_entityArea) { + l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), + 4, 4); + } + String l_tip = null; + XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, + x_item); + if (null != l_tipGenerator) { + l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series, + x_item); + } + String l_url = null; + XYURLGenerator l_urlGenerator = getURLGenerator(); + if (null != l_urlGenerator) { + l_url = l_urlGenerator.generateURL(x_dataset, x_series, + x_item); + } + XYItemEntity l_entity = new XYItemEntity(l_entityArea, x_dataset, + x_series, x_item, l_tip, l_url); + l_entities.add(l_entity); + } + + // draw the item label if there is one... + if (isItemLabelVisible(x_series, x_item)) { + drawItemLabel(x_graphics, l_orientation, x_dataset, x_series, + x_item, l_x1, l_y1, (l_y1 < 0.0)); + } + + int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis); + int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis); + updateCrosshairValues(x_crosshairState, l_x0, l_y0, l_domainAxisIndex, + l_rangeAxisIndex, l_x1, l_y1, l_orientation); + + if (0 == x_item) { + return; + } + + double l_x2 = x_domainAxis.valueToJava2D(x_dataset.getXValue(x_series, + (x_item - 1)), x_dataArea, l_domainAxisLocation); + double l_y2 = x_rangeAxis.valueToJava2D(x_dataset.getYValue(x_series, + (x_item - 1)), x_dataArea, l_rangeAxisLocation); + + Line2D l_line = null; + if (PlotOrientation.HORIZONTAL == l_orientation) { + l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2); + } + else if (PlotOrientation.VERTICAL == l_orientation) { + l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2); + } + + if ((null != l_line) && l_line.intersects(x_dataArea)) { + x_graphics.setPaint(getItemPaint(x_series, x_item)); + x_graphics.setStroke(getItemStroke(x_series, x_item)); + if (drawOriginalSeries) { + x_graphics.setPaint(this.outlinePaint); + x_graphics.setStroke(this.outlineStroke); + x_graphics.draw(l_line); + } + } + } + + /** + * Determines if a dataset is degenerate. A degenerate dataset is a + * dataset where either series has less than two (2) points. + * + * @param x_dataset the dataset. + * @param x_impliedZeroSubtrahend if false, do not check the subtrahend + * + * @return true if the dataset is degenerate. + */ + private boolean isEitherSeriesDegenerate(XYDataset x_dataset, + boolean x_impliedZeroSubtrahend) { + + if (x_impliedZeroSubtrahend) { + return (x_dataset.getItemCount(0) < 2); + } + + return ((x_dataset.getItemCount(0) < 2) + || (x_dataset.getItemCount(1) < 2)); + } + + /** + * Determines if the two (2) series are disjoint. + * Disjoint series do not overlap in the domain space. + * + * @param x_dataset the dataset. + * + * @return true if the dataset is degenerate. + */ + private boolean areSeriesDisjoint(XYDataset x_dataset) { + + int l_minuendItemCount = x_dataset.getItemCount(0); + double l_minuendFirst = x_dataset.getXValue(0, 0); + double l_minuendLast = x_dataset.getXValue(0, l_minuendItemCount - 1); + + int l_subtrahendItemCount = x_dataset.getItemCount(1); + double l_subtrahendFirst = x_dataset.getXValue(1, 0); + double l_subtrahendLast = x_dataset.getXValue(1, + l_subtrahendItemCount - 1); + + return ((l_minuendLast < l_subtrahendFirst) + || (l_subtrahendLast < l_minuendFirst)); + } + + + public void updateCentroid(Object [] xValues, Object [] yValues) { + double x = 0d, y = 0d; + + for (int i = 0, N = xValues.length; i < N; ++i) { + x += ((Double)xValues[i]).doubleValue(); + y += ((Double)yValues[i]).doubleValue(); + } + + x /= xValues.length; + y /= yValues.length; + + centroidNPoints++; + double factorNew = 1d / centroidNPoints; + double factorOld = 1d - factorNew; + + centroid = new Point2D.Double((factorNew * x + factorOld * centroid.x), + (factorNew * y + factorOld * centroid.y)); + } + + + public static double calculateArea(Object [] xValues, Object [] yValues) { + double area = 0d; + + for (int i = 0, N = xValues.length; i < N; ++i) { + int j = (i + 1) % N; + double xi = ((Double)xValues[i]).doubleValue(); + double yi = ((Double)yValues[i]).doubleValue(); + double xj = ((Double)xValues[j]).doubleValue(); + double yj = ((Double)yValues[j]).doubleValue(); + + area += xi*yj; + area -= xj*yi; + // TODO centroid calculation here? + } + + return 0.5d*area; + } + + /** + * Draws the visual representation of a polygon + * + * @param x_graphics the graphics device. + * @param x_dataArea the area within which the data is being drawn. + * @param x_plot the plot (can be used to obtain standard color + * information etc). + * @param x_domainAxis the domain (horizontal) axis. + * @param x_rangeAxis the range (vertical) axis. + * @param x_positive indicates if the polygon is positive (true) or + * negative (false). + * @param x_xValues a linked list of the x values (expects values to be + * of type Double). + * @param x_yValues a linked list of the y values (expects values to be + * of type Double). + */ + private void createPolygon (Graphics2D x_graphics, + Rectangle2D x_dataArea, + XYPlot x_plot, + ValueAxis x_domainAxis, + ValueAxis x_rangeAxis, + boolean x_positive, + LinkedList x_xValues, + LinkedList x_yValues) { + + PlotOrientation l_orientation = x_plot.getOrientation(); + RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); + RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); + + Object[] l_xValues = x_xValues.toArray(); + Object[] l_yValues = x_yValues.toArray(); + + double area = calculateArea(l_xValues, l_yValues)/2d; + if (x_positive) positiveArea += area; + else negativeArea += area; + updateCentroid(l_xValues, l_yValues); + + GeneralPath l_path = new GeneralPath(); + + if (PlotOrientation.VERTICAL == l_orientation) { + double l_x = x_domainAxis.valueToJava2D(( + (Double) l_xValues[0]).doubleValue(), x_dataArea, + l_domainAxisLocation); + if (this.roundXCoordinates) { + l_x = Math.rint(l_x); + } + + double l_y = x_rangeAxis.valueToJava2D(( + (Double) l_yValues[0]).doubleValue(), x_dataArea, + l_rangeAxisLocation); + + l_path.moveTo((float) l_x, (float) l_y); + for (int i = 1; i < l_xValues.length; i++) { + l_x = x_domainAxis.valueToJava2D(( + (Double) l_xValues[i]).doubleValue(), x_dataArea, + l_domainAxisLocation); + if (this.roundXCoordinates) { + l_x = Math.rint(l_x); + } + + l_y = x_rangeAxis.valueToJava2D(( + (Double) l_yValues[i]).doubleValue(), x_dataArea, + l_rangeAxisLocation); + l_path.lineTo((float) l_x, (float) l_y); + } + l_path.closePath(); + } + else { + double l_x = x_domainAxis.valueToJava2D(( + (Double) l_xValues[0]).doubleValue(), x_dataArea, + l_domainAxisLocation); + if (this.roundXCoordinates) { + l_x = Math.rint(l_x); + } + + double l_y = x_rangeAxis.valueToJava2D(( + (Double) l_yValues[0]).doubleValue(), x_dataArea, + l_rangeAxisLocation); + + l_path.moveTo((float) l_y, (float) l_x); + for (int i = 1; i < l_xValues.length; i++) { + l_x = x_domainAxis.valueToJava2D(( + (Double) l_xValues[i]).doubleValue(), x_dataArea, + l_domainAxisLocation); + if (this.roundXCoordinates) { + l_x = Math.rint(l_x); + } + + l_y = x_rangeAxis.valueToJava2D(( + (Double) l_yValues[i]).doubleValue(), x_dataArea, + l_rangeAxisLocation); + l_path.lineTo((float) l_y, (float) l_x); + } + l_path.closePath(); + } + + if (l_path.intersects(x_dataArea)) { + x_graphics.setPaint(x_positive ? getPositivePaint() + : getNegativePaint()); + x_graphics.fill(l_path); + if (drawOutline) { + x_graphics.setStroke(this.outlineStroke); + x_graphics.setPaint(this.outlinePaint); + x_graphics.draw(l_path); + } + } + } + + /** + * Returns a default legend item for the specified series. Subclasses + * should override this method to generate customised items. + * + * @param datasetIndex the dataset index (zero-based). + * @param series the series index (zero-based). + * + * @return A legend item for the series. + */ + public LegendItem getLegendItem(int datasetIndex, int series) { + LegendItem result = null; + XYPlot p = getPlot(); + if (p != null) { + XYDataset dataset = p.getDataset(datasetIndex); + if (dataset != null) { + if (getItemVisible(series, 0)) { + String label = getLegendItemLabelGenerator().generateLabel( + dataset, series); + String description = label; + String toolTipText = null; + if (getLegendItemToolTipGenerator() != null) { + toolTipText + = getLegendItemToolTipGenerator().generateLabel( + dataset, series); + } + String urlText = null; + if (getLegendItemURLGenerator() != null) { + urlText = getLegendItemURLGenerator().generateLabel( + dataset, series); + } + // Individualized Paints: + //Paint paint = lookupSeriesPaint(series); + + // "Area-Style"- Paint. + Paint paint = getPositivePaint(); + Stroke stroke = lookupSeriesStroke(series); + Shape line = getLegendLine(); + // Not-filled Shape: + //result = new LegendItem(label, description, + // toolTipText, urlText, line, stroke, paint); + + if (drawOutline) { + // TODO Include outline style in legenditem (there is a constructor for that) + } + + // Filled Shape ("Area-Style"). + result = new LegendItem(label, description, + toolTipText, urlText, line, paint); + result.setLabelFont(lookupLegendTextFont(series)); + Paint labelPaint = lookupLegendTextPaint(series); + if (labelPaint != null) { + result.setLabelPaint(labelPaint); + } + result.setDataset(dataset); + result.setDatasetIndex(datasetIndex); + result.setSeriesKey(dataset.getSeriesKey(series)); + result.setSeriesIndex(series); + } + } + + } + + return result; + } + + /** + * Tests this renderer for equality with an arbitrary object. + * + * @param obj the object (<code>null</code> permitted). + * + * @return A boolean. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof StableXYDifferenceRenderer)) { + return false; + } + if (!super.equals(obj)) { + return false; + } + StableXYDifferenceRenderer that = (StableXYDifferenceRenderer) obj; + if (!PaintUtilities.equal(this.positivePaint, that.positivePaint)) { + return false; + } + if (!PaintUtilities.equal(this.negativePaint, that.negativePaint)) { + return false; + } + if (this.shapesVisible != that.shapesVisible) { + return false; + } + if (!ShapeUtilities.equal(this.legendShape, that.legendShape)) { + return false; + } + if (this.roundXCoordinates != that.roundXCoordinates) { + return false; + } + return true; + } + + /** + * Returns a clone of the renderer. + * + * @return A clone. + * + * @throws CloneNotSupportedException if the renderer cannot be cloned. + */ + public Object clone() throws CloneNotSupportedException { + StableXYDifferenceRenderer clone = (StableXYDifferenceRenderer) super.clone(); + clone.legendShape = ShapeUtilities.clone(this.legendShape); + return clone; + } + + /** + * Provides serialization support. + * + * @param stream the output stream. + * + * @throws IOException if there is an I/O error. + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + SerialUtilities.writePaint(this.positivePaint, stream); + SerialUtilities.writePaint(this.negativePaint, stream); + SerialUtilities.writeShape(this.legendShape, stream); + } + + /** + * Provides serialization support. + * + * @param stream the input stream. + * + * @throws IOException if there is an I/O error. + * @throws ClassNotFoundException if there is a classpath problem. + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + this.positivePaint = SerialUtilities.readPaint(stream); + this.negativePaint = SerialUtilities.readPaint(stream); + this.legendShape = SerialUtilities.readShape(stream); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,140 @@ +package de.intevation.flys.jfree; + +import org.apache.log4j.Logger; + + +/** + * Custom Annotations class that is drawn only if no collisions with other + * already drawn CustomAnnotations in current plot are found. A mark on + * the axis is shown in all cases, though. + * Draws a given text and a line to it from either axis. + */ +public class StickyAxisAnnotation { + + /** Logger for this class. */ + private static Logger logger = + Logger.getLogger(StickyAxisAnnotation.class); + + /** Simplified view on axes. */ + public static enum SimpleAxis { + X_AXIS, /** Usually "horizontal". */ + Y_AXIS, /** Usually "vertical". */ + Y_AXIS2 + } + + /** The "symbolic" integer representing which axis to stick to. */ + protected int axisSymbol; + + /** Which axis to stick to. */ + protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS; + + /** The 1-dimensional position of this annotation. */ + protected float pos; + + /** + * Optional field used when from axis a line should be drawn that + * hits a curve or something similar (current scenario: duration curves). + * This value is in the "other" dimension than the pos - field. + */ + protected float hitPoint; + + /** The text to display at axis. */ + String text; + + + /** + * Constructor with implicit sticky x-axis. + * @param text the text to display. + * @param pos the position at which to draw the text and mark. + */ + public StickyAxisAnnotation(String text, float pos) { + this(text, pos, SimpleAxis.X_AXIS); + } + + + /** + * Constructor with given explicit axis. + * @param text the text to display. + * @param pos the position at which to draw the text and mark. + * @param stickAxis the axis at which to stick (and to which 'pos' is + * relative). + */ + public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis + ) { + this(text, pos, stickAxis, 0); + } + + + /** + * Constructor with given explicit axis and axisSymbol + * @param text the text to display. + * @param pos the position at which to draw the text and mark. + * @param stickAxis the axis at which to stick (and to which 'pos' is + * relative). + */ + public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis, + int axisSymbol + ) { + setStickyAxis(stickAxis); + this.text = text; + this.pos = pos; + this.axisSymbol = axisSymbol; + this.hitPoint = Float.NaN; + } + + + /** + * Sets the "sticky axis" (whether to draw annotations at the + * X- or the Y-Axis. + * + * @param stickyAxis axis to stick to. + */ + public void setStickyAxis(SimpleAxis stickyAxis) { + this.stickyAxis = stickyAxis; + } + + + public float getPos() { + return this.pos; + } + + public SimpleAxis getStickyAxis() { + return this.stickyAxis; + } + + public boolean atX() { + return this.getStickyAxis() == SimpleAxis.X_AXIS; + } + + /** Get text to be displayed at axis. */ + public String getText() { + return this.text; + } + + + public int getAxisSymbol() { + return this.axisSymbol; + } + + + /** Set where to hit a curve (if any). */ + public void setHitPoint(float pos) { + this.hitPoint = pos; + } + + /** Get where to hit a curve (if any). */ + public float getHitPoint() { + return this.hitPoint; + } + + /** Set sticky axis to the X axis if it is currently Y, and vice versa. */ + public void flipStickyAxis() { + if (this.getStickyAxis() == SimpleAxis.X_AXIS) { + this.setStickyAxis(SimpleAxis.Y_AXIS); + } + else { + this.setStickyAxis(SimpleAxis.X_AXIS); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/Style.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,15 @@ +package de.intevation.flys.jfree; + +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface Style { + + XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx); + + XYLineAndShapeRenderer getRenderer(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,164 @@ +package de.intevation.flys.jfree; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Stroke; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeriesCollection; +import org.w3c.dom.Document; + +import de.intevation.flys.themes.ThemeAccess; +import de.intevation.flys.utils.ThemeUtil; + + +/** + * One or more dataseries to draw a polygon (either "open up/downwards", or + * the area between two curves), a theme-document and further display options. + * The theme-document will later "style" the graphical representation. + * The display options can be used to control the z-order and the axis of the + * dataset. + */ +public class StyledAreaSeriesCollection extends XYSeriesCollection { + /** Mode, how to draw/which areas to fill. */ + public enum FILL_MODE {UNDER, ABOVE, BETWEEN}; + + /** MODE in use. */ + protected FILL_MODE mode; + + /** The theme-document with attributes about actual visual representation. */ + protected Document theme; + + /** Own logger. */ + private static final Logger logger = + Logger.getLogger(StyledAreaSeriesCollection.class); + + + /** + * @param theme the theme-document. + */ + public StyledAreaSeriesCollection(Document theme) { + this.theme = theme; + this.mode = FILL_MODE.BETWEEN; + } + + + /** Gets the Fill mode. */ + public FILL_MODE getMode() { + return this.mode; + } + + + /** Sets the Fill mode. */ + public void setMode(FILL_MODE fMode) { + this.mode = fMode; + } + + + /** + * Applies line color, size and type attributes to renderer, also + * whether to draw lines and/or points. + * @param renderer Renderer to apply theme to. + * @return \param renderer + */ + public StableXYDifferenceRenderer applyTheme( + StableXYDifferenceRenderer renderer + ) { + applyFillColor(renderer); + applyShowShape(renderer); + applyOutlineColor(renderer); + applyOutlineStyle(renderer); + applyShowArea(renderer); + if (mode == FILL_MODE.UNDER) { + renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA); + } + else if (mode == FILL_MODE.ABOVE) { + renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA); + } + else { + renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_ALL_AREA); + } + + // Apply text style. + new ThemeAccess(theme).parseTextStyle().apply(renderer); + return renderer; + } + + + /** + * Blindly (for now) apply the positivepaint of renderer. + */ + protected void applyFillColor(StableXYDifferenceRenderer renderer) { + // Get color. + Color paint = ThemeUtil.parseFillColorField(theme); + // Get half-transparency flag. + if (ThemeUtil.parseTransparency(theme)) { + paint = new Color(paint.getRed(), paint.getGreen(), paint.getBlue(), + 128); + } + if (paint != null && this.getMode() == FILL_MODE.ABOVE) { + renderer.setPositivePaint(paint); + renderer.setNegativePaint(new Color(0,0,0,0)); + } + else if (paint != null && this.getMode() == FILL_MODE.UNDER) { + renderer.setNegativePaint(paint); + renderer.setPositivePaint(new Color(0,0,0,0)); + } + else { + if (paint == null) paint = new Color(177, 117, 102); + renderer.setPositivePaint(paint); + renderer.setNegativePaint(paint); + } + } + + /** + * Blindly (for now) apply the postiviepaint of renderer. + */ + protected void applyShowShape(StableXYDifferenceRenderer renderer) { + boolean show = ThemeUtil.parseShowBorder(theme); + renderer.setDrawOutline(show); + } + + + protected void applyShowLine(StableXYDifferenceRenderer renderer) { + boolean show = ThemeUtil.parseShowLine(theme); + renderer.setShapesVisible(show); + } + + + protected void applyOutlineColor(StableXYDifferenceRenderer renderer) { + Color c = ThemeUtil.parseLineColorField(theme); + renderer.setOutlinePaint(c); + } + + protected void applyOutlineWidth(StableXYDifferenceRenderer renderer) { + int size = ThemeUtil.parseLineWidth(theme); + } + + /** Inform renderer whether it should draw a label. */ + protected void applyShowArea(StableXYDifferenceRenderer renderer) { + renderer.setLabelArea(ThemeUtil.parseShowArea(theme)); + } + + protected void applyOutlineStyle(StableXYDifferenceRenderer renderer) { + float[] dashes = ThemeUtil.parseLineStyle(theme); + int size = ThemeUtil.parseLineWidth(theme); + + Stroke stroke = null; + + if (dashes.length <= 1) { + stroke = new BasicStroke(Integer.valueOf(size)); + } + else { + stroke = new BasicStroke(Integer.valueOf(size), + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, + 1.0f, + dashes, + 0.0f); + } + + renderer.setOutlineStroke(stroke); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,49 @@ +package de.intevation.flys.jfree; + +import java.awt.Color; + +import org.jfree.chart.plot.IntervalMarker; +import org.w3c.dom.Document; + +import de.intevation.flys.utils.ThemeUtil; + +/** + * Marker that represents a highlighted interval. + * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a> + */ +public class StyledDomainMarker extends IntervalMarker { + + private static final long serialVersionUID = -4369417661339512342L; + + private final Color fillColor, backgroundColor; + + public StyledDomainMarker(double start, double end, Document theme) { + super(start, end); + + backgroundColor = ThemeUtil.parseColor( + ThemeUtil.getBackgroundColorString(theme)); + fillColor = ThemeUtil.parseColor( + ThemeUtil.getFillColorString(theme)); + useSecondColor(false); + + int alpha = 100 - ThemeUtil.parseInteger(ThemeUtil.getTransparency(theme), 50); + setAlpha(alpha / 100.0f); + } + + /** + * To properly differentiate several styled domain markers side by side, + * we can use this switch to toggle between two colors. + * @param secondColor + */ + public void useSecondColor(boolean secondColor) { + if(secondColor) { + if(backgroundColor != null) + setPaint(backgroundColor); + } + else { + if(fillColor != null) + setPaint(fillColor); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledSeries.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,13 @@ +package de.intevation.flys.jfree; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface StyledSeries { + + void setStyle(Style style); + + Style getStyle(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledTimeSeries.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,39 @@ +package de.intevation.flys.jfree; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import org.jfree.data.time.TimeSeries; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class StyledTimeSeries extends TimeSeries implements StyledSeries { + + private static final Logger logger = + Logger.getLogger(StyledTimeSeries.class); + + + protected Style style; + + + public StyledTimeSeries(String key, Document theme) { + super(key); + setStyle(new XYStyle(theme)); + } + + + @Override + public void setStyle(Style style) { + this.style = style; + } + + + @Override + public Style getStyle() { + return style; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledValueMarker.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,32 @@ +package de.intevation.flys.jfree; + +import de.intevation.flys.utils.ThemeUtil; + +import java.awt.BasicStroke; +import java.awt.Color; + +import org.jfree.chart.plot.ValueMarker; +import org.w3c.dom.Document; + +/** + * Marker that represents a single value. + * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a> + */ +public class StyledValueMarker extends ValueMarker { + + private static final long serialVersionUID = -3607777705307785140L; + + public StyledValueMarker(double value, Document theme) { + super(value); + + Color color = ThemeUtil.parsePointColor(theme); + if(color == null) { + color = Color.BLACK; + } + this.setPaint(color); + + int size = ThemeUtil.parsePointWidth(theme); + setStroke(new BasicStroke(size)); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StyledXYSeries.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,82 @@ +package de.intevation.flys.jfree; + +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import org.jfree.data.xy.XYDataItem; +import org.jfree.data.xy.XYSeries; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class StyledXYSeries extends XYSeries implements StyledSeries, HasLabel { + + private static final Logger logger = Logger.getLogger(StyledXYSeries.class); + + protected Style style; + + /** If this Series is to be labelled, use this String as label. */ + protected String label; + + + public StyledXYSeries(String key, Document theme) { + this(key, true, theme); + this.label = key.toString(); + } + + + public StyledXYSeries(String key, Document theme, XYSeries unstyledSeries) { + this(key, theme); + add(unstyledSeries); + } + + + /** + * @param sorted whether or not to sort the points. Sorting will move NANs + * to one extrema which can cause problems in certain + * algorithms. + */ + public StyledXYSeries(String key, boolean sorted, Document theme) { + super(key, sorted); + setStyle(new XYStyle(theme)); + this.label = key.toString(); + } + + + @Override + public void setStyle(Style style) { + this.style = style; + } + + + @Override + public Style getStyle() { + return style; + } + + + @Override + public String getLabel() { + return label; + } + + @Override + public void setLabel(String label) { + this.label = label; + } + + protected void add(XYSeries series) { + List<XYDataItem> items = series.getItems(); + add(items); + } + + protected void add(List<XYDataItem> items) { + for(XYDataItem item : items) { + add(item.getXValue(), item.getYValue()); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/TimeBounds.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,88 @@ +package de.intevation.flys.jfree; + +import java.util.Date; + +import org.jfree.chart.axis.DateAxis; +import org.jfree.chart.axis.ValueAxis; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class TimeBounds implements Bounds { + + protected long lower; + protected long upper; + + + public TimeBounds(long lower, long upper) { + this.lower = lower; + this.upper = upper; + } + + + @Override + public Number getLower() { + return Long.valueOf(lower); + } + + + public Date getLowerAsDate() { + return new Date(lower); + } + + + @Override + public Number getUpper() { + return Long.valueOf(upper); + } + + + public Date getUpperAsDate() { + return new Date(upper); + } + + + @Override + public void applyBounds(ValueAxis axis) { + DateAxis dateAxis = (DateAxis) axis; + + dateAxis.setMinimumDate(new Date(lower)); + dateAxis.setMaximumDate(new Date(upper)); + } + + + @Override + public void applyBounds(ValueAxis axis, int percent) { + DateAxis dateAxis = (DateAxis) axis; + + long space = (upper - lower) / 100 * percent; + + dateAxis.setMinimumDate(new Date(lower-space)); + dateAxis.setMaximumDate(new Date(upper+space)); + } + + + @Override + public Bounds combine(Bounds bounds) { + if (bounds == null) { + return this; + } + + TimeBounds other = (TimeBounds) bounds; + + long otherLower = other.getLower().longValue(); + long otherUpper = other.getUpper().longValue(); + + return new TimeBounds( + otherLower < lower ? otherLower : lower, + otherUpper > upper ? otherUpper : upper); + } + + + @Override + public String toString() { + return "TimeBounds=["+ getLowerAsDate() + " ; " + getUpperAsDate() +"]"; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/XYStyle.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,229 @@ +package de.intevation.flys.jfree; + +import de.intevation.flys.utils.ThemeUtil; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.geom.Ellipse2D; + +import org.apache.log4j.Logger; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.w3c.dom.Document; + + +/** + * Utility to apply theme-settings to a renderer. + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class XYStyle implements Style { + + private static Logger logger = Logger.getLogger(XYStyle.class); + + protected Document theme; + + protected XYLineAndShapeRenderer renderer; + + + public XYStyle(Document theme) { + this.theme = theme; + this.renderer = null; + } + + + /** + * Applies line color, size and type attributes to renderer, also + * whether to draw lines and/or points. + */ + @Override + public XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx){ + this.renderer = r; + applyLineColor(r, idx); + applyLineSize(r, idx); + applyLineType(r, idx); + applyShowLine(r, idx); + applyShowPoints(r, idx); + applyPointSize(r, idx); + applyPointColor(r, idx); + applyShowMinimum(r, idx); + applyShowMaximum(r, idx); + + // Line label styles + applyShowLineLabel(r, idx); + applyShowLineLabelBG(r, idx); + applyLineLabelFont(r, idx); + applyLineLabelColor(r, idx); + applyLineLabelBGColor(r, idx); + + // Point label styles + // TODO: Currently point label are annotations and are not drawn this way + /* + applyShowPointLabelBG(r, idx); + applyLinePointFont(r, idx); + applyLinePointColor(r, idx); + applyLinePointBGColor(r, idx);*/ + + return r; + } + + + /** Set line color to renderer. */ + protected void applyLineColor(XYLineAndShapeRenderer r, int idx) { + Color c = ThemeUtil.parseLineColorField(theme); + if(c != null) { + logger.debug("applyLineColor " + c.toString()); + r.setSeriesPaint(idx, c); + } + else { + logger.warn("applyLineColor: color is null - malformed linecolor field?"); + } + } + + + /** Tells the renderer whether or not to add a label to a line. */ + protected void applyShowLineLabel(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + boolean showLabelLine = ThemeUtil.parseShowLineLabel(theme); + boolean anyLabel = showLabelLine || ThemeUtil.parseShowWidth(theme) || + ThemeUtil.parseShowLevel(theme) || + ThemeUtil.parseShowMiddleHeight(theme); + ((EnhancedLineAndShapeRenderer)r).setShowLineLabel(anyLabel, idx); + } + + + /** Tells the renderer whether or not to fill the bg of a lines label. */ + protected void applyShowLineLabelBG(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + boolean showLabelLine = ThemeUtil.parseLabelShowBackground(theme); + ((EnhancedLineAndShapeRenderer)r).setShowLineLabelBG(idx, showLabelLine); + } + + /** Tell the renderer which font (and -size and -style) to use for + * linelabels. */ + protected void applyLineLabelFont(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + ((EnhancedLineAndShapeRenderer)r).setLineLabelFont( + ThemeUtil.parseTextFont(theme), idx); + } + + /** Tell the renderer which color to use for + * linelabels. */ + protected void applyLineLabelColor(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + ((EnhancedLineAndShapeRenderer)r).setLineLabelTextColor( + idx, ThemeUtil.parseTextColor(theme)); + } + + /** Tell the renderer which color to use for bg of + * linelabels. */ + protected void applyLineLabelBGColor(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + ((EnhancedLineAndShapeRenderer)r).setLineLabelBGColor(idx, + ThemeUtil.parseTextBackground(theme)); + } + + /** Set stroke of series. */ + protected void applyLineSize(XYLineAndShapeRenderer r, int idx) { + int size = ThemeUtil.parseLineWidth(theme); + r.setSeriesStroke( + idx, + new BasicStroke(size)); + } + + + /** Set stroke strength of series. */ + protected void applyLineType(XYLineAndShapeRenderer r, int idx) { + int size = ThemeUtil.parseLineWidth(theme); + float[] dashes = ThemeUtil.parseLineStyle(theme); + + // Do not apply the dashed style. + if (dashes.length <= 1) { + return; + } + + r.setSeriesStroke( + idx, + new BasicStroke(size, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, + 1.0f, + dashes, + 0.0f)); + } + + + protected void applyPointSize(XYLineAndShapeRenderer r, int idx) { + int size = ThemeUtil.parsePointWidth(theme); + int dim = 2 * size; + + r.setSeriesShape(idx, new Ellipse2D.Double(-size, -size, dim, dim)); + } + + + protected void applyPointColor(XYLineAndShapeRenderer r, int idx) { + Color c = ThemeUtil.parsePointColor(theme); + + if (c != null) { + r.setSeriesFillPaint(idx, c); + r.setUseFillPaint(true); + r.setDrawOutlines(false); + } + } + + + /** + * Sets form and visibility of points. + */ + protected void applyShowPoints(XYLineAndShapeRenderer r, int idx) { + boolean show = ThemeUtil.parseShowPoints(theme); + + r.setSeriesShapesVisible(idx, show); + r.setDrawOutlines(true); + } + + + protected void applyShowLine(XYLineAndShapeRenderer r, int idx) { + boolean show = ThemeUtil.parseShowLine(theme); + r.setSeriesLinesVisible(idx, show); + } + + + protected void applyShowMinimum(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + + boolean visible = ThemeUtil.parseShowMinimum(theme); + + EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r; + er.setIsMinimumShapeVisisble(idx, visible); + } + + + protected void applyShowMaximum(XYLineAndShapeRenderer r, int idx) { + if (!(r instanceof EnhancedLineAndShapeRenderer)) { + return; + } + + boolean visible = ThemeUtil.parseShowMaximum(theme); + + EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r; + er.setIsMaximumShapeVisible(idx, visible); + } + + + @Override + public XYLineAndShapeRenderer getRenderer() { + return this.renderer; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultTheme.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,187 @@ +package de.intevation.flys.themes; + +import java.util.HashMap; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DefaultTheme implements Theme { + + /** The name of the theme.*/ + protected String name; + + /** The description of the theme.*/ + protected String description; + + protected String facet; + + protected int index; + + + /** The map storing the fields of this theme.*/ + protected Map<String, ThemeField> fields; + + /** The map storing the attributes of this theme.*/ + protected Map<String, String> attr; + + + /** + * Initializes the components of this Theme. + */ + public DefaultTheme(String name, String description) { + this.name = name; + this.description = description; + this.fields = new HashMap<String, ThemeField>(); + this.attr = new HashMap<String, String>(); + } + + + public void init(Node config) { + } + + + public String getName() { + return name; + } + + + public String getDescription() { + return description; + } + + + public String getFacet() { + return facet; + } + + + public void setFacet(String facet) { + this.facet = facet; + } + + + public int getIndex() { + return index; + } + + + public void setIndex(int index) { + this.index = index; + } + + + public void addAttribute(String name, String value) { + if (name != null && value != null) { + attr.put(name, value); + } + } + + + public String getAttribute(String name) { + return attr.get(name); + } + + + public void addField(String name, ThemeField field) { + if (name != null && field != null) { + fields.put(name, field); + } + } + + + public void setFieldValue(String name, Object value) { + if (name != null && value != null) { + ThemeField field = fields.get(name); + + if (field != null) { + field.setValue(value); + } + } + } + + + public ThemeField getField(String name) { + return fields.get(name); + } + + + public String getFieldType(String name) { + ThemeField field = fields.get(name); + + return field != null ? field.getType() : null; + } + + + public Object getFieldValue(String name) { + ThemeField field = fields.get(name); + + return field != null ? field.getValue() : null; + } + + + public Document toXML() { + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator(doc, null, null); + + Element theme = cr.create("theme"); + theme.setAttribute("facet", facet); + theme.setAttribute("index", String.valueOf(index)); + + appendAttributes(cr, theme); + appendFields(cr, theme); + + doc.appendChild(theme); + + return doc; + } + + + /** + * Appends the attributes configured for this theme. + * + * @param cr The ElementCreator. + * @param theme The document root element. + */ + protected void appendAttributes(ElementCreator cr, Element theme) { + + for (Map.Entry<String, String> entry: attr.entrySet()) { + String key = entry.getKey(); + String val = entry.getValue(); + + if (key != null && val != null) { + cr.addAttr(theme, key, val); + } + } + } + + + /** + * Appends the fields configured for this theme. + * + * @param cr The ElementCreator. + * @param theme The document root element. + */ + protected void appendFields(ElementCreator cr, Element theme) { + + for (Map.Entry<String, ThemeField> entry: fields.entrySet()) { + String name = entry.getKey(); + ThemeField field = entry.getValue(); + + Document doc = field.toXML(); + Node root = doc.getFirstChild(); + + theme.appendChild(theme.getOwnerDocument().importNode(root, true)); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultThemeField.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,79 @@ +package de.intevation.flys.themes; + +import java.util.HashMap; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class DefaultThemeField implements ThemeField { + + protected String name; + + protected Map<String, Object> attr; + + + public DefaultThemeField(String name) { + this.name = name; + this.attr = new HashMap<String, Object>(); + } + + + public String getName() { + return name; + } + + + public String getType() { + return (String) getAttribute("type"); + } + + + public Object getValue() { + return getAttribute("value"); + } + + + public void setValue(Object value) { + setAttribute("value", value); + } + + + public Object getAttribute(String name) { + return attr.get(name); + } + + + public void setAttribute(String name, Object value) { + if (name == null || value == null) { + return; + } + + attr.put(name, value); + } + + + public Document toXML() { + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator(doc, null, null); + + Element field = cr.create("field"); + + for (Map.Entry<String, Object> entry: attr.entrySet()) { + cr.addAttr(field, entry.getKey(), (String)entry.getValue()); + } + + doc.appendChild(field); + + return doc; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/LineStyle.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,21 @@ +package de.intevation.flys.themes; + +import java.awt.Color; + +public class LineStyle { + protected Color lineColor; + protected int lineWidth; + + public LineStyle(Color color, int width) { + this.lineColor = color; + this.lineWidth = width; + } + + public int getWidth() { + return lineWidth; + } + + public Color getColor() { + return lineColor; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/PointStyle.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,5 @@ +package de.intevation.flys.themes; + +public class PointStyle { + // TODO tbd +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/TextStyle.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,52 @@ +package de.intevation.flys.themes; + +import de.intevation.flys.jfree.StableXYDifferenceRenderer; + +import java.awt.Color; +import java.awt.Font; + +import org.apache.log4j.Logger; +import org.jfree.chart.annotations.XYTextAnnotation; + +public class TextStyle { + @SuppressWarnings("unused") + private static Logger log = Logger.getLogger(TextStyle.class); + + protected Color textColor; + protected Font font; + protected Color bgColor; + protected boolean showBg; + protected boolean isVertical; + + public TextStyle(Color fgColor, Font font, Color bgColor, + boolean showBg, boolean isVertical + ) { + this.textColor = fgColor; + this.font = font; + this.bgColor = bgColor; + this.showBg = showBg; + this.isVertical = isVertical; + } + + public void apply(XYTextAnnotation ta) { + ta.setPaint(textColor); + ta.setFont(font); + if (this.showBg) { + ta.setBackgroundPaint(bgColor); + } + if (this.isVertical) { + ta.setRotationAngle(270f*Math.PI/180f); + } + else { + ta.setRotationAngle(0); + } + } + + public void apply(StableXYDifferenceRenderer renderer) { + renderer.setLabelColor(textColor); + renderer.setLabelFont(font); + if (this.showBg) { + renderer.setLabelBGColor(bgColor); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/Theme.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,119 @@ +package de.intevation.flys.themes; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface Theme { + + /** + * Method to initialize the theme. + * + * @param config The configuration node. + */ + void init(Node config); + + + /** + * Returns the name of the theme. + * + * @return the name of the theme. + */ + String getName(); + + + /** + * Returns the description of the theme. + * + * @return the description of the theme. + */ + String getDescription(); + + + String getFacet(); + + void setFacet(String facet); + + int getIndex(); + + void setIndex(int index); + + + /** + * Adds a new attribute. + * + * @param name The name of the attribute. + * @param value The value of the attribute. + */ + void addAttribute(String name, String value); + + + /** + * Returns the value of a specific attribute. + * + * @param name the name of the attribute. + * + * @return the value of the attribute <i>name</i>. + */ + String getAttribute(String name); + + + /** + * Adds a new field to the theme. + * + * @param name The name of the field. + * @param field The field. + */ + void addField(String name, ThemeField field); + + + /** + * Sets the value of an field. + * + * @param name The name of the field. + * @param value The new value of the field. + */ + void setFieldValue(String name, Object value); + + + /** + * Returns the field specified by name. + * + * @param name The name of the desired field. + * + * @return an field. + */ + ThemeField getField(String name); + + + /** + * Returns the typename of a field. + * + * @param name the name of the field. + * + * @return the typename of a field. + */ + String getFieldType(String name); + + + /** + * Returns the value of a field. + * + * @param name The name of the field. + * + * @return the value of a field. + */ + Object getFieldValue(String name); + + + /** + * Dumps the theme to XML. + * + * @return a document. + */ + Document toXML(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeAccess.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,124 @@ +package de.intevation.flys.themes; + +import de.intevation.flys.utils.ThemeUtil; + +import java.awt.Color; +import java.awt.Font; + +import org.w3c.dom.Document; + + +public class ThemeAccess +{ + protected Document theme; + + protected Integer lineWidth; + + protected Color lineColor; + protected Color textColor; + protected Font font; + protected String textOrientation; + protected Color textBackground; + protected Boolean showTextBackground; + protected Color pointColor; + + + public ThemeAccess(Document theme) { + this.theme = theme; + } + + + public int parseLineWidth() { + if (lineWidth == null) { + lineWidth = ThemeUtil.parseLineWidth(theme); + } + return lineWidth; + } + + + public Color parseLineColorField() { + if (lineColor == null) { + lineColor = ThemeUtil.parseLineColorField(theme); + if (lineColor == null) { + lineColor = Color.BLACK; + } + } + return lineColor; + } + + + public Color parseTextColor() { + if (textColor == null) { + textColor = ThemeUtil.parseTextColor(theme); + if (textColor == null) { + textColor = Color.BLACK; + } + } + return textColor; + } + + + public Font parseTextFont() { + if (font == null) { + font = ThemeUtil.parseTextFont(theme); + if (font == null) { + font = new Font("Arial", Font.BOLD, 10); + } + } + return font; + } + + + public String parseTextOrientation() { + if (textOrientation == null) { + textOrientation = ThemeUtil.parseTextOrientation(theme); + } + return textOrientation; + } + + + public Color parseTextBackground() { + if (textBackground == null) { + textBackground = ThemeUtil.parseTextBackground(theme); + if (textBackground == null) { + textBackground = Color.WHITE; + } + } + return textBackground; + } + + public boolean parseLabelShowBackground() { + if (showTextBackground == null) { + showTextBackground = ThemeUtil.parseLabelShowBackground(theme); + } + return showTextBackground; + } + + + public Color parsePointColor() { + if (pointColor == null) { + pointColor = ThemeUtil.parsePointColor(theme); + + if (pointColor == null) { + return parseLineColorField(); + } + } + + return pointColor; + } + + + public LineStyle parseLineStyle() { + return new LineStyle(parseLineColorField(), Integer.valueOf(parseLineWidth())); + } + + public TextStyle parseTextStyle() { + return new TextStyle( + parseTextColor(), + parseTextFont(), + parseTextBackground(), + parseLabelShowBackground(), + !parseTextOrientation().equals("horizontal")); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeFactory.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,312 @@ +package de.intevation.flys.themes; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.context.FLYSContext; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + * + * Mapping-matching rules: + * + */ +public class ThemeFactory { + + private static Logger logger = Logger.getLogger(ThemeFactory.class); + + /** Trivial, hidden constructor. */ + private ThemeFactory() { + } + + + /** + * Creates a new theme from <i>config</i>. + * + * @param themeCfg The theme config document that is used to fetch parent + * themes. + * @param config The theme config node. + * + * @return a new theme. + */ + public static Theme createTheme(Document themeCfg, Node config) { + String name = getName(config); + String desc = getDescription(config); + + logger.debug("Create new theme: " + name); + + Theme theme = new DefaultTheme(name, desc); + + parseInherits(themeCfg, config, theme); + parseFields(config, theme); + parseAttrs(config, theme); + + return theme; + } + + + /** + * Get first matching theme for facet. + * + * @param name Name to match "from" of theme mapping. + * @param pattern String to 'compare' to pattern in mapping. + * @param output Name of the current output + * + * @return First matching theme. + */ + public static Theme getTheme( + FLYSContext c, + String name, + String pattern, + String output, + String groupName) + { + if (logger.isDebugEnabled()) { + logger.debug( + "Search theme for: " + name + " - pattern: " + pattern); + } + + if (c == null || name == null) { + logger.warn("Cannot search for theme."); + return null; + } + + // Fetch mapping and themes. + @SuppressWarnings("unchecked") + Map<String, List<ThemeMapping>> map = (Map<String, List<ThemeMapping>>) + c.get(FLYSContext.THEME_MAPPING); + + @SuppressWarnings("unchecked") + List<ThemeGroup> tgs = (List<ThemeGroup>) + c.get(FLYSContext.THEMES); + + ThemeGroup group = null; + for (ThemeGroup tg: tgs) { + if (tg.getName().equals(groupName)) { + group = tg; + break; + } + } + + if (group == null) { + logger.warn("No theme group found: '" + groupName + "'"); + return null; + } + + Map<String, Theme> t = group.getThemes(); + + FLYSArtifact artifact = (FLYSArtifact) c.get(FLYSContext.ARTIFACT_KEY); + + if (map == null || map.isEmpty() || t == null || t.isEmpty()) { + logger.warn("No mappings or themes found. Cannot retrieve theme!"); + return null; + } + + List<ThemeMapping> mapping = map.get(name); + + if (mapping == null) { + logger.warn("No theme found for mapping: " + name); + return null; + } + + // Take first mapping of which all conditions are satisfied. + for (ThemeMapping tm: mapping) { + if (name.equals(tm.getFrom()) + && tm.applyPattern(pattern) + && tm.masterAttrMatches(artifact) + && tm.outputMatches(output)) + { + String target = tm.getTo(); + + logger.debug("Found theme '" + target + "'"); + return t.get(target); + } + } + + String msg = + "No theme found for '" + name + + "' with pattern '" + pattern + "' and output " + output + "."; + + logger.warn(msg); + + return null; + } + + + @SuppressWarnings("unchecked") + public static List<ThemeGroup> getThemeGroups(FLYSContext c) { + List<ThemeGroup> tgs = (List<ThemeGroup>) + c.get(FLYSContext.THEMES); + return tgs; + } + + + @SuppressWarnings("unchecked") + public static List<Theme> getThemes (FLYSContext c, String name) { + List<ThemeGroup> tgs = (List<ThemeGroup>) + c.get(FLYSContext.THEMES); + if (tgs == null) { + return null; + } + + List<Theme> themes = new ArrayList<Theme>(); + for (ThemeGroup tg: tgs) { + themes.add(tg.getThemeByName(name)); + } + return themes; + } + + protected static String getName(Node config) { + return ((Element)config).getAttribute("name"); + } + + + protected static String getDescription(Node config) { + return ((Element)config).getAttribute("desc"); + } + + + protected static void parseInherits(Document themeCfg, Node cfg, Theme t) { + parseInherits(themeCfg, cfg, t, null); + } + + protected static void parseInherits( + Document themeCfg, + Node cfg, + Theme t, + Map<String, Node> themes + ) { + logger.debug("ThemeFactory.parseInherits"); + + NodeList inherits = ((Element)cfg).getElementsByTagName("inherit"); + + int num = inherits.getLength(); + + if (num == 0) { + logger.debug("Theme does not inherit from other themes."); + return; + } + + logger.debug("Theme inherits from " + num + " other themes."); + + if (themes == null) { + themes = buildThemeMap(themeCfg); + } + + for (int i = 0; i < num; i++) { + Node inherit = inherits.item(i); + String from = ((Element)inherit).getAttribute("from"); + + Node tmp = themes.get(from); + + parseInherits(themeCfg, tmp, t, themes); + parseFields(tmp, t); + } + } + + protected static Map<String, Node> buildThemeMap(Document themeCfg) { + Map<String, Node> map = new HashMap<String, Node>(); + String xpath = "/themes/themegroup/theme"; + + NodeList nodes = (NodeList)XMLUtils.xpath( + themeCfg, xpath, XPathConstants.NODESET); + + if (nodes != null) { + for (int i = 0, N = nodes.getLength(); i < N; ++i) { + Node node = nodes.item(i); + String name = ((Element)node).getAttribute("name"); + map.put(name, node); + } + } + return map; + } + + + protected static void parseFields(Node config, Theme theme) { + if (config == null || theme == null) { + logger.warn("Parsing fields without node or theme is senseless!"); + return; + } + + NodeList fields = ((Element)config).getElementsByTagName("field"); + + int num = fields.getLength(); + + logger.debug("Found " + num + " own fields in this theme."); + + if (num == 0) { + logger.debug("Theme has no own fields."); + return; + } + + for (int i = 0; i < num; i++) { + Node field = fields.item(i); + + addField(theme, field); + } + } + + + protected static void addField(Theme theme, Node field) { + String name = ((Element)field).getAttribute("name"); + + logger.debug("Add field " + name + " to theme " + theme.getName()); + + NamedNodeMap attrs = field.getAttributes(); + + int num = attrs != null ? attrs.getLength() : 0; + + if (num == 0) { + logger.warn("This field has no attributes."); + return; + } + + ThemeField theField = new DefaultThemeField(name); + + for (int i = 0; i < num; i++) { + Node attr = attrs.item(i); + + String key = attr.getNodeName(); + String value = attr.getNodeValue(); + + theField.setAttribute(key, value); + } + + theme.addField(name, theField); + } + + + protected static void parseAttrs(Node config, Theme theme) { + NamedNodeMap attrs = config.getAttributes(); + + int num = attrs != null ? attrs.getLength() : 0; + + if (num == 0) { + logger.debug("Theme has no attributes set."); + return; + } + + for (int i = 0; i < num; i++) { + Node attr = attrs.item(i); + + String name = attr.getNodeName(); + String value = attr.getNodeValue(); + + theme.addAttribute(name, value); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeField.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,58 @@ +package de.intevation.flys.themes; + +import org.w3c.dom.Document; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public interface ThemeField { + + /** + * Returns the name of this field. + * + * @return the name of this field. + */ + String getName(); + + /** + * Returns the type of this field. + * + * @return the type of this field. + */ + String getType(); + + + /** + * Returns the value of this field. + * + * @return the value of this field. + */ + Object getValue(); + + + /** + * Changes the value of this field. + * + * @param value The new value. + */ + void setValue(Object value); + + + /** + * Sets the value of an attribute. + * + * @param name The name of an attribute. + * @param value The value of an attribute. + */ + void setAttribute(String name, Object value); + + + /** + * Dumps the field to XML. + * + * @return a document. + */ + Document toXML(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeGroup.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,32 @@ +package de.intevation.flys.themes; + +import java.util.Map; + +/** + * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> + */ +public class ThemeGroup { + + protected String name; + + protected Map<String, Theme> themes; + + + public ThemeGroup(String name, Map<String, Theme> themes) { + this.name = name; + this.themes = themes; + } + + public String getName() { + return this.name; + } + + public Map<String, Theme> getThemes() { + return this.themes; + } + + public Theme getThemeByName(String name) { + return themes.get(name); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeMapping.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,158 @@ +package de.intevation.flys.themes; + +import org.apache.log4j.Logger; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.intevation.flys.artifacts.FLYSArtifact; + +/** + * Represents mapping to a theme (including conditions). + */ +public class ThemeMapping implements Serializable { + + /** The logger that is used in this class */ + private static Logger logger = Logger.getLogger(ThemeMapping.class); + + /** Name from which to map. */ + protected String from; + + /** Name to which to map. */ + protected String to; + + /** Given pattern (held against facet description). */ + protected String patternStr; + + /** Given masterAttr pattern (held against masterartifacts attributes). */ + protected String masterAttr; + + /** Given output for which mapping is valid. */ + protected String output; + + protected Pattern pattern; + + + public ThemeMapping(String from, String to) { + this(from, to, null, null, null); + } + + + public ThemeMapping( + String from, + String to, + String patternStr, + String masterAttr, + String output) + { + this.from = from; + this.to = to; + this.patternStr = patternStr; + this.masterAttr = masterAttr; + this.output = output; + + this.pattern = Pattern.compile(patternStr); + } + + + public String getFrom() { + return from; + } + + + /** + * Get name of theme that is mapped to. + */ + public String getTo() { + return to; + } + + + /** + * Get pattern. + */ + public String getPatternStr() { + return patternStr; + } + + + /** + * Match regular expression against text. + * + * @param text string to be matched against. + * @return true if pattern matches text or pattern is empty. + */ + public boolean applyPattern(String text) { + if (patternStr == null || patternStr.length() == 0) { + return true; + } + Matcher m = pattern.matcher(text); + + if (m.matches()) { + logger.debug("Pattern matches: " + text); + return true; + } + else { + logger.debug( + "Pattern '"+ text + "' does not match: " + this.patternStr); + return false; + } + } + + + /** + * Inspects Artifacts data given the masterAttr-condition. + * + * The only condition implemented so far is 'key==value', for which + * the Artifacts data with name "key" has to be of value "value" in order + * for true to be returned. + * + * @param artifact Artifact of which to inspect data. + * @return true if no condition is specified or condition is met. + */ + public boolean masterAttrMatches(FLYSArtifact artifact) { + if (masterAttr == null || masterAttr.length() == 0) { + return true; + } + + // Operator split. + String[] parts = masterAttr.split("=="); + if (parts.length != 2) { + logger.error("ThemeMapping could not parse masterAttr.-condition:_" + + masterAttr + "_"); + return false; + } + + // Test. + if (artifact.getDataAsString(parts[0]).equals(parts[1])) { + logger.debug("Matches master Attribute."); + return true; + } + else { + logger.debug("Does not match master Attribute."); + return false; + } + } + + + /** + * Returns true if no output condition exists, or the condition is met + * in parameter output. + */ + public boolean outputMatches(String output) { + if (this.output == null || this.output.length() == 0) { + return true; + } + + if (this.output.equals(output)) { + logger.debug("Output matches this mapping: " + output); + return true; + } + else { + logger.debug("Output '"+ output +"' does not match: "+ this.output); + return false; + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DataUtil.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,34 @@ +package de.intevation.flys.utils; + +import java.util.Random; + +import gnu.trove.TDoubleArrayList; + +public class DataUtil +{ + public static boolean guessWaterIncreasing(TDoubleArrayList data) { + return guessWaterIncreasing(data, 0.05f); + } + + public static boolean guessWaterIncreasing(TDoubleArrayList data, float factor) { + int N = data.size(); + if (N < 2) return false; + + int samples = (int)(factor*N) + 1; + + int up = 0; + + Random rand = new Random(); + + for (int i = 0; i < samples; ++i) { + int pos2 = rand.nextInt(N-1) + 1; + int pos1 = rand.nextInt(pos2); + double w1 = data.getQuick(pos1); + double w2 = data.getQuick(pos2); + if (w2 > w1) ++up; + } + + return up > samples/2; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DateAverager.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,36 @@ +package de.intevation.flys.utils; + +import gnu.trove.TLongArrayList; + +import java.util.Date; + +public class DateAverager +{ + protected TLongArrayList dates; + + public DateAverager() { + dates = new TLongArrayList(); + } + + public void add(Date date) { + dates.add(date.getTime()); + } + + public Date getAverage() { + int N = dates.size(); + if (N == 0) { + return null; + } + long min = dates.min(); + long sum = 0L; + for (int i = 0; i < N; ++i) { + sum += dates.getQuick(i) - min; + } + return new Date(min + (long)Math.round(sum/(double)N)); + } + + public void clear() { + dates.resetQuick(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DoubleUtil.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,192 @@ +package de.intevation.flys.utils; + +import de.intevation.flys.artifacts.math.Linear; + +import gnu.trove.TDoubleArrayList; + +import java.util.Arrays; + +import org.apache.log4j.Logger; + +public class DoubleUtil +{ + private static Logger log = Logger.getLogger(DoubleUtil.class); + + public static final double DEFAULT_STEP_PRECISION = 1e6; + + private DoubleUtil() { + } + + public static final double [] explode(double from, double to, double step) { + return explode(from, to, step, DEFAULT_STEP_PRECISION); + } + + public static final double round(double x, double precision) { + return Math.round(x * precision)/precision; + } + + public static final double round(double x) { + return Math.round(x * DEFAULT_STEP_PRECISION)/DEFAULT_STEP_PRECISION; + } + + public static final double [] explode( + double from, + double to, + double step, + double precision + ) { + double lower = from; + + double diff = to - from; + double tmp = diff / step; + int num = (int)Math.abs(Math.ceil(tmp)) + 1; + + double [] values = new double[num]; + + if (from > to) { + step = -step; + } + + double max = Math.max(from, to); + + for (int idx = 0; idx < num; idx++) { + if (lower > max) { + return Arrays.copyOfRange(values, 0, idx); + } + + values[idx] = round(lower, precision); + lower += step; + } + + return values; + } + + public static final double interpolateSorted( + double [] xs, + double [] ys, + double x + ) { + int lo = 0, hi = xs.length-1; + + int mid = -1; + + while (lo <= hi) { + mid = (lo + hi) >> 1; + double mx = xs[mid]; + if (x < mx) hi = mid - 1; + else if (x > mx) lo = mid + 1; + else return ys[mid]; + } + if (mid < lo) { + return lo >= xs.length + ? Double.NaN + : Linear.linear(x, xs[mid], xs[mid+1], ys[mid], ys[mid+1]); + } + return hi < 0 + ? Double.NaN + : Linear.linear(x, xs[mid-1], xs[mid], ys[mid-1], ys[mid]); + } + + public static final boolean isIncreasing(double [] array) { + int inc = 0; + int dec = 0; + int sweet = (array.length-1)/2; + for (int i = 1; i < array.length; ++i) { + if (array[i] > array[i-1]) { + if (++inc > sweet) { + return true; + } + } + else if (++dec > sweet) { + return false; + } + } + return inc > sweet; + } + + public static final double [] swap(double [] array) { + int lo = 0; + int hi = array.length-1; + while (hi > lo) { + double t = array[lo]; + array[lo] = array[hi]; + array[hi] = t; + ++lo; + --hi; + } + + return array; + } + + public static final double [] swapClone(double [] in) { + double [] out = new double[in.length]; + + for (int j = out.length-1, i = 0; j >= 0;) { + out[j--] = in[i++]; + } + + return out; + } + + public static final double [] sumDiffs(double [] in) { + double [] out = new double[in.length]; + + for (int i = 1; i < out.length; ++i) { + out[i] = out[i-1] + Math.abs(in[i-1] - in[i]); + } + + return out; + } + + public static final double [] fill(int N, double value) { + double [] result = new double[N]; + Arrays.fill(result, value); + return result; + } + + public interface SegmentCallback { + void newSegment(double from, double to, double [] values); + } + + public static final void parseSegments( + String input, + SegmentCallback callback + ) { + TDoubleArrayList vs = new TDoubleArrayList(); + + for (String segmentStr: input.split(":")) { + String [] parts = segmentStr.split(";"); + if (parts.length < 3) { + log.warn("invalid segment: '" + segmentStr + "'"); + continue; + } + try { + double from = Double.parseDouble(parts[0].trim()); + double to = Double.parseDouble(parts[1].trim()); + + vs.resetQuick(); + + for (String valueStr: parts[2].split(",")) { + vs.add(round(Double.parseDouble(valueStr.trim()))); + } + + callback.newSegment(from, to, vs.toNativeArray()); + } + catch (NumberFormatException nfe) { + log.warn("invalid segment: '" + segmentStr + "'"); + } + } + } + + public static final boolean isValid(double [][] data) { + for (double [] ds: data) { + for (double d: ds) { + if (Double.isNaN(d)) { + return false; + } + } + } + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,930 @@ +package de.intevation.flys.utils; + +import org.apache.log4j.Logger; + +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.xpath.XPathConstants; + +import org.w3c.dom.Document; + +import org.hibernate.SessionFactory; +import org.hibernate.impl.SessionFactoryImpl; + +import gnu.trove.TDoubleArrayList; +import gnu.trove.TIntArrayList; +import gnu.trove.TLongArrayList; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.Config; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.backend.SessionFactoryProvider; + +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.artifacts.model.LocationProvider; +import de.intevation.flys.artifacts.model.WQ; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.artifactdatabase.state.State; +import de.intevation.flys.artifacts.states.WaterlevelSelectState; +import de.intevation.flys.artifacts.states.WDifferencesState; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.MainValue; +import de.intevation.flys.model.River; + + +/** static helper methods to e.g. access FLYSArtifacts data. */ +public class FLYSUtils { + + /** The logger that is used in this utility. */ + private static Logger logger = Logger.getLogger(FLYSUtils.class); + + public static enum KM_MODE { RANGE, LOCATIONS, NONE }; + + /** + * An enum that represents the 5 possible WQ modes in FLYS. The 5 values are + * <i>QFREE</i> <i>QGAUGE</i> <i>WGAUGE</i> <i>WFREE</i> and <i>NONE</i>. + */ + public static enum WQ_MODE { QFREE, QGAUGE, WFREE, WGAUGE, NONE }; + + /** + * An enum that represents the 4 possible WQ input modes in FLYS. The 4 + * values are + * <i>ADAPTED</i> <i>SINGLE</i> <i>RANGE</i> and <i>NONE</i>. + */ + public static enum WQ_INPUT { ADAPTED, SINGLE, RANGE, NONE }; + + public static final Pattern NUMBERS_PATTERN = + Pattern.compile("\\D*(\\d++.\\d*)\\D*"); + + public static final String XPATH_RIVER_PROJECTION = + "/artifact-database/floodmap/river[@name=$name]/srid/@value"; + + public static final String XPATH_SHAPEFILE_DIR = + "/artifact-database/floodmap/shapefile-path/@value"; + + public static final String XPATH_VELOCITY_LOGFILE = + "/artifact-database/floodmap/velocity/logfile/@path"; + + public static final String XPATH_MAPSERVER_URL = + "/artifact-database/floodmap/mapserver/server/@path"; + + public static final String XPATH_MAPFILE_PATH = + "/artifact-database/floodmap/mapserver/mapfile/@path"; + + public static final String XPATH_MAPFILE_TEMPLATE = + "/artifact-database/floodmap/mapserver/map-template/@path"; + + public static final String XPATH_MAPSERVER_TEMPLATE_PATH = + "/artifact-database/floodmap/mapserver/templates/@path"; + + + private FLYSUtils() { + } + + + /** + * Pulls Artifact with given UUID fromm database. + * @return FLYSArtifact with given UUID or null (in case of errors). + */ + public static FLYSArtifact getArtifact(String uuid, CallContext context) { + try { + Artifact artifact = context.getDatabase().getRawArtifact(uuid); + + if (artifact == null) { + logger.error("Artifact '" + uuid + "' does not exist."); + return null; + } + + if (!(artifact instanceof FLYSArtifact)) { + logger.error("Artifact '" +uuid+ "' is no valid FLYSArtifact."); + return null; + } + + return (FLYSArtifact) artifact; + } + // TODO: catch more selective + catch (Exception e) { + logger.error("Cannot get FLYSArtifact " + uuid + + " from database (" + e.getMessage() + ")."); + return null; + } + } + + + /** + * Returns the FLYSContext from context object. + * + * @param context The CallContext or the FLYSContext. + * + * @return the FLYSContext. + */ + public static FLYSContext getFlysContext(Object context) { + return context instanceof FLYSContext + ? (FLYSContext) context + : (FLYSContext) ((CallContext) context).globalContext(); + } + + + /** + * Convinience function to retrieve an XPath as string with replaced config + * directory. + * + * @param xpath The XPath expression. + * + * @return a string with replaced config directory. + */ + public static String getXPathString(String xpath) { + String tmp = Config.getStringXPath(xpath); + tmp = Config.replaceConfigDir(tmp); + + return tmp; + } + + + public static boolean isUsingOracle() { + SessionFactory sf = SessionFactoryProvider.getSessionFactory(); + + String d = SessionFactoryProvider.getDriver((SessionFactoryImpl) sf); + + return d != null ? d.indexOf("Oracle") >= 0 : false; + } + + + /** + * This method returns an WQ_MODE enum which is based on the parameters + * stored in <i>flys</i> Artifact. If there is no <i>wq_isq</i> parameter + * existing, WQ_MODE.NONE is returned. + * + * @param flys The FLYSArtifact that stores wq mode relevant parameters. + * + * @return an enum WQ_MODE. + */ + public static WQ_MODE getWQMode(FLYSArtifact flys) { + if (flys == null) { + return WQ_MODE.NONE; + } + + String values = flys.getDataAsString("wq_values"); + Boolean isQ = flys.getDataAsBoolean("wq_isq"); + + if (values != null) { + return isQ ? WQ_MODE.QGAUGE : WQ_MODE.WGAUGE; + } + + Boolean isFree = flys.getDataAsBoolean("wq_isfree"); + + if (isQ) { + return isFree ? WQ_MODE.QFREE : WQ_MODE.QGAUGE; + } + else if (!isQ) { + return isFree ? WQ_MODE.WFREE : WQ_MODE.WGAUGE; + } + else { + return WQ_MODE.NONE; + } + } + + + public static WQ_INPUT getWQInputMode(FLYSArtifact flys) { + if (flys == null) { + return WQ_INPUT.NONE; + } + + Boolean selection = flys.getDataAsBoolean("wq_isrange"); + String adapted = flys.getDataAsString("wq_values"); + + if(adapted != null && adapted.length() > 0) { + return WQ_INPUT.ADAPTED; + } + + if (selection != null && selection) { + return WQ_INPUT.RANGE; + } + else { + return WQ_INPUT.SINGLE; + } + } + + public static KM_MODE getKmRangeMode(FLYSArtifact flys) { + String mode = flys.getDataAsString("ld_mode"); + + if (mode == null || mode.length() == 0) { + return KM_MODE.NONE; + } + else if (mode.equals("distance")) { + return KM_MODE.RANGE; + } + else if (mode.equals("locations")) { + return KM_MODE.LOCATIONS; + } + else { + return KM_MODE.NONE; + } + } + + /** + * Get min and max kilometer, independent of parametization + * (ld_from/to vs ld_locations). + */ + public static double[] getKmRange(FLYSArtifact flys) { + switch (getKmRangeMode(flys)) { + case RANGE: { + return getKmFromTo(flys); + } + + case LOCATIONS: { + double[] locs = getLocations(flys); + return new double[] { locs[0], locs[locs.length-1] }; + } + + case NONE: { + double[] locs = getLocations(flys); + if (locs != null) { + return new double[] { locs[0], locs[locs.length-1] }; + } + else { + return getKmFromTo(flys); + } + } + } + + return new double[] { Double.NaN, Double.NaN }; + } + + + /** + * Get bounds for river of artifact. + * @param flysArtifact artifact which has a "river" data. + * @return double array. min is at[0], max at[1]. null if given artifact is null + */ + public static double[] getRiverMinMax(FLYSArtifact flysArtifact) { + if (flysArtifact == null) { + return null; + } + + String riverName = flysArtifact.getDataAsString("river"); + + if (riverName == null) { + riverName = ""; + } + + logger.debug("Search for the min/max distances of '" + riverName + "'"); + + River river = RiverFactory.getRiver(riverName); + + return river != null + ? river.determineMinMaxDistance() + : null; + } + + + public static double[] getKmFromTo(FLYSArtifact flys) { + String strFrom = flys.getDataAsString("ld_from"); + String strTo = flys.getDataAsString("ld_to"); + + if (strFrom == null) { + strFrom = flys.getDataAsString("from"); + } + + if (strTo == null) { + strTo = flys.getDataAsString("to"); + } + + if (strFrom == null || strTo == null) { + return null; + } + + try { + return new double[] { + Double.parseDouble(strFrom), + Double.parseDouble(strTo) }; + } + catch (NumberFormatException nfe) { + return null; + } + } + + + /** + * Return sorted array of locations at which stuff was calculated + * (from ld_locations data), null if not parameterized this way. + */ + public static double[] getLocations(FLYSArtifact flys) { + String locationStr = flys.getDataAsString("ld_locations"); + + if (locationStr == null || locationStr.length() == 0) { + if (flys instanceof WINFOArtifact) { + WINFOArtifact winfo = (WINFOArtifact) flys; + if (winfo.getReferenceStartKm() != null) { + return new double[] + { + winfo.getReferenceStartKm().doubleValue(), + winfo.getReferenceEndKms()[0] + }; + } + } + return null; + } + + String[] tmp = locationStr.split(" "); + TDoubleArrayList locations = new TDoubleArrayList(); + + for (String l: tmp) { + try { + locations.add(Double.parseDouble(l)); + } + catch (NumberFormatException nfe) { + } + } + + locations.sort(); + + return locations.toNativeArray(); + } + + + /** + * Returns the Qs for a given FLYSArtifact. This method currently accepts + * only instances of WINFOArtifact. + * + * @param flys A FLYSArtifact. + * + * @return the Qs. + */ + public static double[] getQs(FLYSArtifact flys) { + // XXX this is not nice! + if (flys instanceof WINFOArtifact) { + return ((WINFOArtifact) flys).getQs(); + } + + logger.warn("This method currently supports WINFOArtifact only!"); + + return null; + } + + + /** + * Returns the Ws for a given FLYSArtifact. This method currently accepts + * only instances of WINFOArtifact. + * + * @param flys A FLYSArtifact. + * + * @return the Ws. + */ + public static double[] getWs(FLYSArtifact flys) { + // XXX this is not nice! + if (flys instanceof WINFOArtifact) { + return ((WINFOArtifact) flys).getWs(); + } + + logger.warn("This method currently supports WINFOArtifact only!"); + + return null; + } + + + /** + * Returns the selected River object based on the 'river' data that might + * have been inserted by the user. + * + * @return the selected River or null if no river has been chosen yet. + */ + public static River getRiver(FLYSArtifact flys) { + String sRiver = getRivername(flys); + + return (sRiver != null) + ? RiverFactory.getRiver(sRiver) + : null; + } + + + /** + * Returns the name of the river specified in the given <i>flys</i> + * Artifact. + * + * @param flys The FLYSArtifact that stores a river relevant information. + * + * @return the name of the specified river or null. + */ + public static String getRivername(FLYSArtifact flys) { + return flys != null ? flys.getDataAsString("river") : null; + } + + + /** + * Extracts the SRID defined in the global configuration for the river + * specified in <i>artifact</i>. + * + * @param artifact The FLYSArtifact that stores the name of the river. + * + * @return the SRID as string (e.g. "31466"). + */ + public static String getRiverSrid(FLYSArtifact artifact) { + String river = artifact.getDataAsString("river"); + + if (river == null || river.length() == 0) { + return null; + } + + return getRiverSrid(river); + } + + + public static String getRiverSrid(String rivername) { + Map<String, String> variables = new HashMap<String, String>(1); + variables.put("name", rivername); + + Document cfg = Config.getConfig(); + + return (String) XMLUtils.xpath( + cfg, + XPATH_RIVER_PROJECTION, + XPathConstants.STRING, + null, + variables); + } + + + /** + * Return the (first) Gauge corresponding to the given location(s) of + * the artifact. + * @param flys the artifact in question. + * @return (First) gauge of locations of river of artifact. + */ + public static Gauge getGauge(FLYSArtifact flys) { + River river = getRiver(flys); + + if (river == null) { + logger.debug("no river found"); + return null; + } + + double[] dist = getKmRange(flys); + + if (dist == null) { + logger.debug("no range found"); + return null; + } + + if (logger.isDebugEnabled()) { + logger.debug("Determine gauge for:"); + logger.debug("... river: " + river.getName()); + logger.debug("... distance: " + dist[0] + " - " + dist[1]); + } + + Gauge gauge = river.determineGauge(dist[0], dist[1]); + + String name = gauge != null ? gauge.getName() : "'n/a"; + logger.debug("Found gauge: " + name); + + return gauge; + } + + + public static String getGaugename(FLYSArtifact flys) { + Gauge gauge = getGauge(flys); + + return gauge != null ? gauge.getName() : null; + } + + + public static Gauge getReferenceGauge(FLYSArtifact flys) { + Long officialNumber = flys.getDataAsLong("reference_gauge"); + + return officialNumber != null + ? Gauge.getGaugeByOfficialNumber(officialNumber) + : null; + } + + + public static String getReferenceGaugeName(FLYSArtifact flys) { + Gauge refGauge = getReferenceGauge(flys); + + return refGauge != null + ? refGauge.getName() + : "-- not found --"; + } + + + public static Double getValueFromWQ(WQ wq) { + if (wq == null) { + return null; + } + + Matcher m = NUMBERS_PATTERN.matcher(wq.getName()); + + if (m.matches()) { + logger.debug("Found a number."); + + String raw = m.group(1); + + try { + return Double.valueOf(raw); + } + catch (NumberFormatException nfe) { + } + } + + return null; + } + + + public static String createWspWTitle( + WINFOArtifact winfo, + CallContext cc, + String name + ) { + String[] parts = name.split("="); + + NumberFormat nf = Formatter.getWaterlevelW(cc); + + String namedMainValue = null; + + boolean isQ = winfo.isQ(); + boolean isFree = winfo.isFreeQ(); + + double v; + + try { + v = Double.valueOf(parts[1]); + + namedMainValue = getNamedMainValue(winfo.getGauge(), v); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse Double of: '" + parts[1] + "'"); + return name; + } + + String prefix = null; + + if (isQ && !isFree && namedMainValue != null) { + return "W (" + namedMainValue + ")"; + } + + if (isQ) { + prefix = "Q="; + } + + return prefix == null + ? "W(" + nf.format(v) + ")" + : "W(" + prefix + nf.format(v) + ")"; + } + + + public static String createWspQTitle( + WINFOArtifact winfo, + CallContext cc, + String name + ) { + String[] parts = name.split("="); + + NumberFormat nf = Formatter.getWaterlevelQ(cc); + + String namedMainValue = null; + + boolean isQ = winfo.isQ(); + boolean isFree = winfo.isFreeQ(); + + double v; + + try { + v = Double.valueOf(parts[1]); + + namedMainValue = getNamedMainValue(winfo.getGauge(), v); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse Double of: '" + parts[1] + "'"); + return name; + } + + String prefix = null; + + if (isQ && !isFree && namedMainValue != null) { + return namedMainValue; + } + + if (!isQ) { + prefix = "W="; + } + + return prefix == null + ? "Q(" + nf.format(v) + ")" + : "Q(" + prefix + nf.format(v) + ")"; + } + + + /** + * Returns the named main value if a Q was selected and if this Q fits to a + * named main value. Otherwise, this function returns null. + * + * @param winfo The WINFO Artifact. + * @param value The Q (or W) value. + * + * @return a named main value or null. + */ + public static String getNamedMainValue(WINFOArtifact winfo, double value) { + WQ_MODE wqmode = getWQMode(winfo); + + if (wqmode != WQ_MODE.QGAUGE) { + return null; + } + else { + return getNamedMainValue(winfo.getGauge(), value); + } + } + + + public static String getNamedMainValue(Gauge gauge, double value) { + List<MainValue> mainValues = gauge.getMainValues(); + logger.debug("Search named main value for: " + value); + + for (MainValue mv: mainValues) { + if (mv.getValue().doubleValue() == value) { + logger.debug("Found named main value: " + mv.getMainValue().getName()); + return mv.getMainValue().getName(); + } + } + + logger.debug("Did not find a named main value for: " + value); + return null; + } + + + /** + * + * @param nmv A string that represents a named main value. + * + * @throws NullPointerException if nmv is null. + */ + public static String stripNamedMainValue(String nmv) { + int startIndex = nmv.indexOf("("); + int endIndex = nmv.indexOf(")"); + + if (startIndex > 0 && endIndex > 0 && startIndex < endIndex) { + return nmv.substring(0, startIndex); + } + + return nmv; + } + + + /** + * Returns the URL of user mapfile for the owner of Artifact + * <i>artifactId</i>. + * + * @param artifactId The UUID of an artifact. + * + * @return the URL of the user wms. + */ + public static String getUserWMSUrl(String artifactId) { + String url = getXPathString(XPATH_MAPSERVER_URL); + url = url.endsWith("/") ? url + "user-wms" : url + "/" + "user-wms"; + + return url; + } + + + /** + * This method returns the description for a given <i>km</i> for a specific + * river. The river is provided by the FLYSArtifact <i>flys</i>. + * + * @param flys The FLYSArtifact that provides a river. + * @param km The kilometer. + * + * @return the description for <i>km</i> or an empty string if no + * description was found. + */ + public static String getLocationDescription(FLYSArtifact flys, double km) { + String river = getRivername(flys); + + if (river == null) { + return ""; + } + + return LocationProvider.getLocation(river, km); + } + + + /** + * This method returns the differences for a w-differences calculation. + * + * @param winfo The WINFOArtifact. + * @param context The context. + * + * @return The differences as string separated by semicolon and linebreak. + */ + public static String getWDifferences( + WINFOArtifact winfo, + CallContext context) + { + State state = winfo.getCurrentState(context); + if(state instanceof WDifferencesState) { + String diffids = winfo.getDataAsString("diffids"); + String datas[] = diffids.split("#"); + + // Validate the Data-Strings. + for (String s: datas) { + if (!WaterlevelSelectState.isValueValid(winfo.getDataAsString("diffids"))) { + return ""; + } + } + + if (datas.length < 2) { + return ""; + } + + String diffs = ""; + for(int i = 0; i < datas.length; i+=2) { + // e.g.: + // 42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;1 + WKms minuendWKms = getWKms(StringUtil.unbracket(datas[i+0]), + context); + WKms subtrahendWKms = getWKms(StringUtil.unbracket(datas[i+1]), + context); + if (minuendWKms != null && subtrahendWKms != null) { + diffs += StringUtil.wWrap(minuendWKms.getName()) + + " - " + StringUtil.wWrap(subtrahendWKms.getName()); + } + diffs += ";\n"; + } + return diffs; + } + else { + logger.warn("Not a valid state for differences."); + return ""; + } + } + + + protected static WKms getWKms(String mingle, CallContext context) { + String[] def = mingle.split(";"); + String uuid = def[0]; + String name = def[1]; + int idx = Integer.parseInt(def[2]); + + if (name.startsWith("staticwkms")) { + StaticWKmsArtifact staticWKms = + (StaticWKmsArtifact) FLYSUtils.getArtifact( + uuid, + context); + WKms wkms = staticWKms.getWKms(idx); + if (wkms == null) + logger.error("No WKms from artifact."); + return wkms; + } + + WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact( + uuid, + context); + + if (flys == null) { + logger.warn("One of the artifacts (1) for diff calculation could not be loaded"); + return null; + } + else{ + WQKms[] wqkms = (WQKms[]) flys.getWaterlevelData(). + getData(); + if (wqkms == null) + logger.warn("not waterlevels in artifact"); + else if (wqkms.length < idx) + logger.warn("not enough waterlevels in artifact"); + return wqkms[idx]; + } + } + + + /** + * This method transform a string into an int array. Therefore, the string + * <i>raw</i> must consist of int values separated by a <i>';'</i>. + * + * @param raw The raw integer array as string separated by a ';'. + * + * @return an array of int values. + */ + public static int[] intArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No integer values found in '" + raw + "'"); + return new int[0]; + } + + TIntArrayList integers = new TIntArrayList(splitted.length); + + for (String value: splitted) { + try { + integers.add(Integer.parseInt(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing integer failed: " + nfe); + } + } + + return integers.toNativeArray(); + } + + + /** + * This method transform a string into a long array. Therefore, the string + * <i>raw</i> must consist of int values separated by a <i>';'</i>. + * + * @param raw The raw long array as string separated by a ';'. + * + * @return an array of int values. + */ + public static long[] longArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No long values found in '" + raw + "'"); + return new long[0]; + } + + TLongArrayList longs = new TLongArrayList(splitted.length); + + for (String value: splitted) { + try { + longs.add(Long.valueOf(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing long failed: " + nfe); + } + } + + return longs.toNativeArray(); + } + + + /** + * This method transform a string into an double array. Therefore, the + * string <i>raw</i> must consist of double values separated by a + * <i>';'</i>. + * + * @param raw The raw double array as string separated by a ';'. + * + * @return an array of double values. + */ + public static double[] doubleArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No double values found in '" + raw + "'"); + return new double[0]; + } + + TDoubleArrayList doubles = new TDoubleArrayList(splitted.length); + + for (String value: splitted) { + try { + doubles.add(Double.valueOf(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing double failed: " + nfe); + } + } + + return doubles.toNativeArray(); + } + + + /** + * Returns the gauges that match the selected kilometer range. + * + * @param flys the flys artifact. + * + * @return the gauges based on the selected kilometer range (null if + * none/no range set). + */ + public static List<Gauge> getGauges(FLYSArtifact flys) { + + River river = getRiver(flys); + if (river == null) { + logger.debug("getGauges: no river!"); + return null; + } + + double [] dist = getKmRange(flys); + if (dist == null) { + logger.debug("getGauges: no dist!"); + return null; + } + logger.debug("getGauges: " + dist[0] + " - " + dist[1]); + + return river.determineGauges(dist[0], dist[1]); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/Formatter.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,400 @@ +package de.intevation.flys.utils; + +import java.text.DateFormat; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.resources.Resources; + + +public final class Formatter { + + // KMS IN ERROR REPORTS. + public static final int CALCULATION_REPORT_KM_MIN_DIGITS = 1; + public static final int CALCULATION_REPORT_KM_MAX_DIGITS = 3; + + // WATERLEVEL FORMATTER CONSTANTS + public static final int WATERLEVEL_KM_MIN_DIGITS = 3; + public static final int WATERLEVEL_KM_MAX_DIGITS = 3; + public static final int WATERLEVEL_W_MIN_DIGITS = 0; + public static final int WATERLEVEL_W_MAX_DIGITS = 2; + public static final int WATERLEVEL_Q_MIN_DIGITS = 0; + public static final int WATERLEVEL_Q_MAX_DIGITS = 2; + + + // COMPUTED DISCHARGE CURVE FORMATTER CONSTANTS + public static final int COMPUTED_DISCHARGE_W_MIN_DIGITS = 2; + public static final int COMPUTED_DISCHARGE_W_MAX_DIGITS = 2; + public static final int COMPUTED_DISCHARGE_Q_MIN_DIGITS = 0; + public static final int COMPUTED_DISCHARGE_Q_MAX_DIGITS = 2; + + + // HISTORICAL DISCHARGE CURVE FORMATTER CONSTANTS + public static final int HISTORICAL_DISCHARGE_W_MIN_DIGITS = 0; + public static final int HISTORICAL_DISCHARGE_W_MAX_DIGITS = 2; + public static final int HISTORICAL_DISCHARGE_Q_MIN_DIGITS = 0; + public static final int HISTORICAL_DISCHARGE_Q_MAX_DIGITS = 2; + + + // DURATION CURVE FORMATTER CONSTANTS + public static final int DURATION_W_MIN_DIGITS = 0; + public static final int DURATION_W_MAX_DIGITS = 2; + public static final int DURATION_Q_MIN_DIGITS = 0; + public static final int DURATION_Q_MAX_DIGITS = 1; + public static final int DURATION_D_MIN_DIGITS = 0; + public static final int DURATION_D_MAX_DIGITS = 0; + + + // FLOW VELOCITY FORMATTER CONSTANTS + public static final int FLOW_VELOCITY_KM_MIN_DIGITS = 3; + public static final int FLOW_VELOCITY_KM_MAX_DIGITS = 3; + public static final int FLOW_VELOCITY_VALUES_MIN_DIGITS = 2; + public static final int FLOW_VELOCITY_VALUES_MAX_DIGITS = 2; + public static final int FLOW_VELOCITY_Q_MIN_DIGITS = 0; + public static final int FLOW_VELOCITY_Q_MAX_DIGITS = 2; + + + // MIDDLE BED HEIGHT FORMATTER CONSTANTS + public static final int MIDDLE_BED_HEIGHT_KM_MIN_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_KM_MAX_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_HEIGHT_MIN_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_HEIGHT_MAX_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_UNCERT_MIN_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_UNCERT_MAX_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_DATAGAP_MIN_DIGITS = 2; + public static final int MIDDLE_BED_HEIGHT_DATAGAP_MAX_DIGITS = 2; + public static final int MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MIN_DIGITS = 0; + public static final int MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MAX_DIGITS = 0; + public static final int MIDDLE_BED_HEIGHT_WIDTH_MIN_DIGITS = 3; + public static final int MIDDLE_BED_HEIGHT_WIDTH_MAX_DIGITS = 3; + + public static final int FIX_DELTA_W_KM_MIN_DIGITS = 3; + public static final int FIX_DELTA_W_KM_MAX_DIGITS = 3; + public static final int FIX_DELTA_W_DELTA_W_MIN_DIGITS = 3; + public static final int FIX_DELTA_W_DELTA_W_MAX_DIGITS = 3; + public static final int FIX_DELTA_W_DELTA_Q_MIN_DIGITS = 0; + public static final int FIX_DELTA_W_DELTA_Q_MAX_DIGITS = 2; + + /** + * Creates a localized NumberFormatter with given range of decimal digits. + * @param m CallMeta to find the locale. + * @param min minimum number of decimal ("fraction") digits. + * @param max maximum number of decimal ("fraction") digits. + * @return A NumberFormat. Use #format(NUMBER) to get String representation + * of NUMBER. + */ + public static NumberFormat getFormatter(CallMeta m, int min, int max){ + Locale locale = Resources.getLocale(m); + NumberFormat nf = NumberFormat.getInstance(locale); + + nf.setMaximumFractionDigits(max); + nf.setMinimumFractionDigits(min); + + return nf; + } + + public static NumberFormat getFormatter(CallContext c, int min, int max){ + return getFormatter(c.getMeta(), min, max); + } + + + /** + * Returns a number formatter with no max or min digits set. + * + * @param c The CallContext. + * + * @return a number formatter. + */ + public static NumberFormat getRawFormatter(CallContext c) { + Locale locale = Resources.getLocale(c.getMeta()); + return NumberFormat.getInstance(locale); + } + + + /** + * Returns a date formatter with SHORT style. + */ + public static DateFormat getShortDateFormat(CallContext cc) { + Locale locale = Resources.getLocale(cc.getMeta()); + return DateFormat.getDateInstance(DateFormat.SHORT, locale); + } + + + /** + * Returns a date formatter with MEDIUM style. + */ + public static DateFormat getMediumDateFormat(CallContext cc) { + Locale locale = Resources.getLocale(cc.getMeta()); + return DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + } + + + /** + * Returns the number formatter for kilometer values in waterlevel exports. + * + * @return the number formatter for kilometer values. + */ + public static NumberFormat getWaterlevelKM(CallContext context) { + return getFormatter( + context, + WATERLEVEL_KM_MIN_DIGITS, + WATERLEVEL_KM_MAX_DIGITS); + } + + public static NumberFormat getWaterlevelW(CallMeta meta) { + return getFormatter( + meta, + WATERLEVEL_W_MIN_DIGITS, + WATERLEVEL_W_MAX_DIGITS); + } + + /** + * Returns the number formatter for W values in waterlevel exports. + * + * @return the number formatter for W values. + */ + public static NumberFormat getWaterlevelW(CallContext context) { + return getFormatter( + context, + WATERLEVEL_W_MIN_DIGITS, + WATERLEVEL_W_MAX_DIGITS); + } + + + /** + * Returns the number formatter for Q values in waterlevel exports. + * + * @return the number formatter for Q values. + */ + public static NumberFormat getWaterlevelQ(CallContext context) { + return getFormatter( + context, + WATERLEVEL_Q_MIN_DIGITS, + WATERLEVEL_Q_MAX_DIGITS); + } + + public static NumberFormat getWaterlevelQ(CallMeta meta) { + return getFormatter( + meta, + WATERLEVEL_Q_MIN_DIGITS, + WATERLEVEL_Q_MAX_DIGITS); + } + + /** + * Returns the number formatter for W values in exports of computed + * discharge curves. + * + * @return the number formatter for W values. + */ + public static NumberFormat getComputedDischargeW(CallContext context) { + return getFormatter( + context, + COMPUTED_DISCHARGE_W_MIN_DIGITS, + COMPUTED_DISCHARGE_W_MAX_DIGITS); + } + + + /** + * Returns the number formatter for Q values in exports of computed + * discharge curves. + * + * @return the number formatter for Q values. + */ + public static NumberFormat getComputedDischargeQ(CallContext context) { + return getFormatter( + context, + COMPUTED_DISCHARGE_Q_MIN_DIGITS, + COMPUTED_DISCHARGE_Q_MAX_DIGITS); + } + + + /** + * Returns the number formatter for W values in exports of historical + * discharge curves. + * + * @return the number formatter for W values. + */ + public static NumberFormat getHistoricalDischargeW(CallContext context) { + return getFormatter( + context, + HISTORICAL_DISCHARGE_W_MIN_DIGITS, + HISTORICAL_DISCHARGE_W_MAX_DIGITS); + } + + + /** + * Returns the number formatter for Q values in exports of historical + * discharge curves. + * + * @return the number formatter for Q values. + */ + public static NumberFormat getHistoricalDischargeQ(CallContext context) { + return getFormatter( + context, + HISTORICAL_DISCHARGE_Q_MIN_DIGITS, + HISTORICAL_DISCHARGE_Q_MAX_DIGITS); + } + + + /** + * Returns the number formatter for W values in duration curve exports. + * + * @return the number formatter for W values. + */ + public static NumberFormat getDurationW(CallContext context) { + return getFormatter( + context, + DURATION_W_MIN_DIGITS, + DURATION_W_MAX_DIGITS); + } + + + /** + * Returns the number formatter for Q values in duration curve exports. + * + * @return the number formatter for W values. + */ + public static NumberFormat getDurationQ(CallContext context) { + return getFormatter( + context, + DURATION_Q_MIN_DIGITS, + DURATION_Q_MAX_DIGITS); + } + + + /** + * Returns the number formatter for D values in duration curve exports. + * + * @return the number formatter for W values. + */ + public static NumberFormat getDurationD(CallContext context) { + return getFormatter( + context, + DURATION_D_MIN_DIGITS, + DURATION_D_MAX_DIGITS); + } + + public static NumberFormat getCalculationKm(CallMeta meta) { + return getFormatter( + meta, + CALCULATION_REPORT_KM_MIN_DIGITS, + CALCULATION_REPORT_KM_MAX_DIGITS); + } + + + public static NumberFormat getFlowVelocityKM(CallContext context) { + return getFormatter( + context, + FLOW_VELOCITY_KM_MIN_DIGITS, + FLOW_VELOCITY_KM_MAX_DIGITS); + } + + + public static NumberFormat getFlowVelocityValues(CallContext context) { + return getFormatter( + context, + FLOW_VELOCITY_VALUES_MIN_DIGITS, + FLOW_VELOCITY_VALUES_MAX_DIGITS); + } + + + public static NumberFormat getFlowVelocityQ(CallContext context) { + return getFormatter( + context, + FLOW_VELOCITY_Q_MIN_DIGITS, + FLOW_VELOCITY_Q_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightKM(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_KM_MIN_DIGITS, + MIDDLE_BED_HEIGHT_KM_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightHeight(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_HEIGHT_MIN_DIGITS, + MIDDLE_BED_HEIGHT_HEIGHT_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightUncert(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_UNCERT_MIN_DIGITS, + MIDDLE_BED_HEIGHT_UNCERT_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightDataGap(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_DATAGAP_MIN_DIGITS, + MIDDLE_BED_HEIGHT_DATAGAP_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightSounding(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MIN_DIGITS, + MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MAX_DIGITS); + } + + + public static NumberFormat getMiddleBedHeightWidth(CallContext context) { + return getFormatter( + context, + MIDDLE_BED_HEIGHT_WIDTH_MIN_DIGITS, + MIDDLE_BED_HEIGHT_WIDTH_MAX_DIGITS); + } + + public static NumberFormat getFixDeltaWKM(CallContext context) { + return getFormatter( + context, + FIX_DELTA_W_KM_MIN_DIGITS, + FIX_DELTA_W_KM_MAX_DIGITS); + } + + public static NumberFormat getFixDeltaWDeltaW(CallContext context) { + return getFormatter( + context, + FIX_DELTA_W_DELTA_W_MIN_DIGITS, + FIX_DELTA_W_DELTA_W_MAX_DIGITS); + } + + public static NumberFormat getFixDeltaWQ(CallContext context) { + return getFormatter( + context, + FIX_DELTA_W_DELTA_Q_MIN_DIGITS, + FIX_DELTA_W_DELTA_Q_MAX_DIGITS); + } + + public static NumberFormat getFixDeltaWW(CallContext context) { + return getFormatter( + context, + FIX_DELTA_W_DELTA_W_MIN_DIGITS, + FIX_DELTA_W_DELTA_W_MAX_DIGITS); + } + + public static NumberFormat getMeterFormat(CallContext context) { + return getFormatter( + context, + 0, + 2); + + } + + public static DateFormat getDateFormatter(CallMeta m, String pattern) { + Locale locale = Resources.getLocale(m); + return new SimpleDateFormat(pattern, locale); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/GeometryUtils.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,375 @@ +package de.intevation.flys.utils; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +import de.intevation.flys.model.RiverAxis; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.geotools.data.DataStoreFactorySpi; +import org.geotools.data.DefaultTransaction; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.ShapefileDataStoreFactory; +import org.geotools.data.simple.SimpleFeatureIterator; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureIterator; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.geojson.feature.FeatureJSON; +import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.CRS; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.NoSuchAuthorityCodeException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; + +public class GeometryUtils { + + private static final Logger logger = Logger.getLogger(GeometryUtils.class); + + public static final String PREFIX_EPSG = "EPSG:"; + + public static final String DEFAULT_EPSG = "EPSG:31467"; + + private GeometryUtils() { + } + + public static Envelope getRiverBoundary(String rivername) { + List<RiverAxis> axes = RiverAxis.getRiverAxis(rivername); + if (axes != null && axes.size() > 0) { + Envelope max = null; + + for (RiverAxis axis: axes) { + // TODO Take the correct EPSG into account. Maybe, we need to + // reproject the geometry. + Envelope env = axis.getGeom().getEnvelopeInternal(); + + if (max == null) { + max = env; + } + else { + max.expandToInclude(env); + } + } + + return max; + } + + return null; + } + + public static String getRiverBounds(String rivername) { + Envelope env = getRiverBoundary(rivername); + + if (env != null) { + return jtsBoundsToOLBounds(env); + } + + return null; + } + + /** + * Returns the boundary of Envelope <i>env</i> in OpenLayers representation. + * + * @param env The envelope of a geometry. + * + * @return the OpenLayers boundary of <i>env</i>. + */ + public static String jtsBoundsToOLBounds(Envelope env) { + StringBuilder buf = new StringBuilder(); + buf.append(env.getMinX()); buf.append(' '); + buf.append(env.getMinY()); buf.append(' '); + buf.append(env.getMaxX()); buf.append(' '); + buf.append(env.getMaxY()); + return buf.toString(); + } + + public static String createOLBounds(Geometry a, Geometry b) { + Coordinate[] ca = a.getCoordinates(); + Coordinate[] cb = b.getCoordinates(); + + double lowerX = Double.MAX_VALUE; + double lowerY = Double.MAX_VALUE; + double upperX = -Double.MAX_VALUE; + double upperY = -Double.MAX_VALUE; + + for (Coordinate c: ca) { + lowerX = lowerX < c.x ? lowerX : c.x; + lowerY = lowerY < c.y ? lowerY : c.y; + + upperX = upperX > c.x ? upperX : c.x; + upperY = upperY > c.y ? upperY : c.y; + } + + for (Coordinate c: cb) { + lowerX = lowerX < c.x ? lowerX : c.x; + lowerY = lowerY < c.y ? lowerY : c.y; + + upperX = upperX > c.x ? upperX : c.x; + upperY = upperY > c.y ? upperY : c.y; + } + + return "" + lowerX + " " + lowerY + " " + upperX + " " + upperY; + } + + public static SimpleFeatureType buildFeatureType( + String name, String srs, Class<?> geometryType) + { + return buildFeatureType(name, srs, geometryType, null); + } + + /** + * Creates a new SimpleFeatureType using a SimpleFeatureTypeBuilder. + * + * @param name The name of the FeatureType. + * @param srs The SRS (e.g. "EPSG:31466"). + * @param geometryType The geometry type's class (e.g. Polygon.class). + * @param attrs Optional. An object with attribute-name/attribute-class pairs + * where index 0 specifies the name as string and index 1 the + * ype as class. + * + * @return a new SimpleFeatureType. + */ + public static SimpleFeatureType buildFeatureType(String name, String srs, + Class<?> geometryType, Object[][] attrs) { + try { + SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); + CoordinateReferenceSystem crs = CRS.decode(srs); + + builder.setName("flys"); + builder.setNamespaceURI("http://www.intevation.de/"); + builder.setCRS(crs); + builder.setSRS(srs); + + builder.add("geometry", geometryType, crs); + + if (attrs != null) { + for (Object[] attr: attrs) { + builder.add((String) attr[0], (Class<?>) attr[1]); + } + } + + return builder.buildFeatureType(); + } + catch (NoSuchAuthorityCodeException nsae) { + } + catch (FactoryException fe) { + } + + return null; + } + + public static List<SimpleFeature> parseGeoJSON( + String geojson, SimpleFeatureType ft + ) { + List<SimpleFeature> collection = new ArrayList<SimpleFeature>(); + + try { + FeatureJSON fjson = new FeatureJSON(); + fjson.setFeatureType(ft); + + FeatureIterator<SimpleFeature> iterator = + fjson.streamFeatureCollection(geojson); + + while (iterator.hasNext()) { + collection.add(iterator.next()); + } + } + catch (IOException ioe) { + // TODO handle exception + } + + return collection; + } + + + /** + * This method returns the {@link CoordinateReferenceSystem} by the + * {@link String} <i>epsg</i>. + * + * @param epsg An EPSG code like <b>EPSG:31466</b> + * + * @return the {@link CoordinateReferenceSystem} specified by <i>epsg</i>. + */ + public static CoordinateReferenceSystem getCoordinateReferenceSystem( + String epsg + ) { + if (epsg == null) { + logger.warn("cannot create CoordinateReferenceSystem with null"); + return null; + } + + if (!epsg.startsWith(PREFIX_EPSG)) { + epsg = PREFIX_EPSG + epsg; + } + + try { + return CRS.decode(epsg); + } + catch (FactoryException fe) { + logger.error( + "unable to get CoordinateReferenceSystem for: " + epsg, + fe); + } + + return null; + } + + + public static Envelope transform(Envelope orig, String targetSrs) { + return transform(orig, targetSrs, DEFAULT_EPSG); + } + + + public static Envelope transform( + Envelope orig, + String targetSrs, + String origSrs + ) { + if (targetSrs == null || orig == null || origSrs == null) { + logger.warn("unable to transform envelope: empty parameters"); + return orig; + } + + logger.debug("Transform envlope to '" + targetSrs + "'"); + try { + CoordinateReferenceSystem sourceCRS = + getCoordinateReferenceSystem(origSrs); + + CoordinateReferenceSystem targetCRS = + getCoordinateReferenceSystem(targetSrs); + + if (sourceCRS != null && targetCRS != null) { + ReferencedEnvelope tmpEnv = + new ReferencedEnvelope(orig, CRS.decode(origSrs)); + + Envelope target = tmpEnv.transform(targetCRS, false); + + if (logger.isDebugEnabled()) { + logger.debug(" orig envelope : " + orig); + logger.debug(" transformed envelope: " + target); + } + + return target; + } + } + catch (NoSuchAuthorityCodeException nsae) { + logger.error("Cannot get CoordinateReferenceSystem!", nsae); + } + catch (FactoryException fe) { + logger.error("Cannot get CoordinateReferenceSystem!", fe); + } + catch (TransformException te) { + logger.error("Cannot transform envelope from source " + + origSrs + " to target srs " + targetSrs); + } + + return null; + } + + + public static boolean writeShapefile(File shape, + SimpleFeatureType featureType, FeatureCollection<?, ?> collection) { + return writeShapefile(shape, featureType, collection, + featureType.getCoordinateReferenceSystem()); + } + + + public static boolean writeShapefile(File shape, + SimpleFeatureType featureType, FeatureCollection<?, ?> collection, + CoordinateReferenceSystem crs) { + if (collection.isEmpty()) { + logger.warn("Shapefile is not written - no features given!"); + return false; + } + + Transaction transaction = null; + + try { + MathTransform transform = CRS.findMathTransform( + CRS.decode(DEFAULT_EPSG), crs); + + Map<String, Serializable> params = + new HashMap<String, Serializable>(); + + params.put("url", shape.toURI().toURL()); + params.put("create spatial index", Boolean.TRUE); + + DataStoreFactorySpi dataStoreFactory = + new ShapefileDataStoreFactory(); + + ShapefileDataStore newDataStore = + (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); + newDataStore.createSchema(featureType); + + transaction = new DefaultTransaction("create"); + + String typeName = newDataStore.getTypeNames()[0]; + + FeatureWriter<SimpleFeatureType, SimpleFeature> writer = + newDataStore.getFeatureWriter(typeName, transaction); + + SimpleFeatureIterator iterator = (SimpleFeatureIterator) collection.features(); + + while (iterator.hasNext()){ + SimpleFeature feature = iterator.next(); + SimpleFeature copy = writer.next(); + + copy.setAttributes(feature.getAttributes()); + + Geometry orig = (Geometry) feature.getDefaultGeometry(); + Geometry reprojected = JTS.transform(orig, transform); + + copy.setDefaultGeometry(reprojected); + writer.write(); + } + + transaction.commit(); + + return true; + } + catch (MalformedURLException mue) { + logger.error("Unable to prepare shapefile: " + mue.getMessage()); + } + catch (IOException ioe) { + logger.error("Unable to write shapefile: " + ioe.getMessage()); + } + catch (NoSuchAuthorityCodeException nsae) { + logger.error("Cannot get CoordinateReferenceSystem for '" + + DEFAULT_EPSG + "'"); + } + catch (FactoryException fe) { + logger.error("Cannot get CoordinateReferenceSystem for '" + + DEFAULT_EPSG + "'"); + } + catch (TransformException te) { + logger.error("Was not able to transform geometry!", te); + } + finally { + if (transaction != null) { + try { + transaction.close(); + } + catch (IOException ioe) { /* do nothing */ } + } + } + + return false; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/IdGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,18 @@ +package de.intevation.flys.utils; + +public class IdGenerator { + + protected int id; + + public IdGenerator() { + } + + public IdGenerator(int id) { + this.id = id; + } + + public int next() { + return id++; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/KMIndex.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,92 @@ +package de.intevation.flys.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Iterator; + +import java.io.Serializable; + +public class KMIndex<A> +implements Serializable, Iterable<KMIndex.Entry<A>> +{ + public static final double EPSILON = 1e-4; + + public static class Entry<A> + implements Serializable, Comparable<Entry<A>> + { + protected double km; + protected A value; + + public Entry(double km) { + this.km = km; + } + + public Entry(double km, A value) { + this.km = km; + this.value = value; + } + + public double getKm() { + return km; + } + + public A getValue() { + return value; + } + + public void setValue(A value) { + this.value = value; + } + + @Override + public int compareTo(Entry<A> other) { + double diff = km - other.km; + if (diff < -EPSILON) return -1; + if (diff > +EPSILON) return +1; + return 0; + } + + public boolean epsilonEquals(double km) { + return Math.abs(this.km - km) < EPSILON; + } + } // class Entry + + + protected List<Entry<A>> entries; + + public KMIndex() { + this(10); + } + + public KMIndex(int capacity) { + entries = new ArrayList<Entry<A>>(capacity); + } + + public void add(double km, A value) { + entries.add(new Entry<A>(km, value)); + } + + public void sort() { + Collections.sort(entries); + } + + public Entry<A> search(double km) { + for (Entry<A> entry: entries) { + if (entry.epsilonEquals(km)) { + return entry; + } + } + return null; + } + + public Entry<A> binarySearch(double km) { + int index = Collections.binarySearch(entries, new Entry<A>(km)); + return index >= 0 ? entries.get(index) : null; + } + + public Iterator<Entry<A>> iterator() { + return entries.iterator(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,758 @@ +package de.intevation.flys.utils; + +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.Config; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.LayerInfo; +import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet; +import de.intevation.flys.artifacts.model.map.WMSLayerFacet; +import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet; +import de.intevation.flys.artifacts.resources.Resources; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.geotools.data.shapefile.ShpFiles; +import org.geotools.data.shapefile.shp.ShapefileHeader; +import org.geotools.data.shapefile.shp.ShapefileReader; + +/** + * This class iterates over a bunch of directories, searches for meta + * information coresponding to shapefiles and creates a mapfile which is used by + * a <i>MapServer</i>. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class MapfileGenerator +extends Thread +{ + public static final String WSPLGEN_RESULT_SHAPE = "wsplgen.shp"; + public static final String WSPLGEN_LINES_SHAPE = "barrier_lines.shp"; + public static final String WSPLGEN_POLYGONS_SHAPE = "barrier_polygons.shp"; + public static final String WSPLGEN_USER_SHAPE = "user-rgd.shp"; + + public static final String WSPLGEN_LAYER_TEMPLATE = "wsplgen_layer.vm"; + public static final String SHP_LAYER_TEMPLATE = "shapefile_layer.vm"; + public static final String DB_LAYER_TEMPLATE = "db_layer.vm"; + + public static final String MS_WSPLGEN_PREFIX = "wsplgen-"; + public static final String MS_BARRIERS_PREFIX = "barriers-"; + public static final String MS_LINE_PREFIX = "lines-"; + public static final String MS_POLYGONS_PREFIX = "polygons-"; + public static final String MS_LAYER_PREFIX = "ms_layer-"; + public static final String MS_USERSHAPE_PREFIX = "user-"; + + protected static final long SLEEPTIME = 10 * 1000L; // 10 seconds + + private static Logger logger = Logger.getLogger(MapfileGenerator.class); + + private static MapfileGenerator instance; + + private File mapfile; + private File shapefileDirectory; + + private String mapServerUrl; + private String templatePath; + private String velocityLogfile; + + private VelocityEngine velocityEngine; + private final boolean lock[]; + + + + private MapfileGenerator() { + lock = new boolean[1]; + } + + + /** + * A main method which can be used to create a mapfile without a running + * artifact server.<br> + * <b>NOTE:</b> This method is not implemented yet! + * + * @param args Arguments. + */ + public static void main(String[] args) { + throw new Error("MapfileGenerator.main() is CURRENTLY NOT IMPLEMENTED!"); + } + + + /** + * Returns the instance of this generator. + * + * @return the instance. + */ + public static synchronized MapfileGenerator getInstance() { + if (instance == null) { + instance = new MapfileGenerator(); + instance.setDaemon(true); + instance.start(); + } + + return instance; + } + + + /** + * Triggers the mapfile generation process. + */ + public void update() { + synchronized (lock) { + logger.debug("update"); + lock[0] = true; + lock.notify(); + } + } + + + /** + * Thread to generate a mapfile. + */ + @Override + public void run() { + logger.debug("Start MapfileGenerator thread..."); + try { + for (;;) { + synchronized (lock) { + while (!lock[0]) { + lock.wait(SLEEPTIME); + } + lock[0] = false; + } + + logger.debug("Start sync process now..."); + generate(); + } + } + catch (InterruptedException ie) { + logger.debug("MapfileGenerator thread got an interrupt."); + } + catch (FileNotFoundException fnfe) { + logger.debug("Error while mapfile creation: " + fnfe.getMessage()); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + finally { + logger.debug("THREAD END"); + } + } + + /** + * Method to check the existance of a template file. + * + * @param templateID The name of a template. + * @return true, of the template exists - otherwise false. + */ + public boolean templateExists(String templateID){ + Template template = getTemplateByName(templateID); + return template != null; + } + + + /** + * Method which starts searching for meta information file and mapfile + * generation. + */ + protected void generate() + throws FileNotFoundException, IOException + { + File[] userDirs = getUserDirs(); + + List<String> layers = parseLayers(userDirs); + + logger.info("Found " + layers.size() + " layers for user mapfile."); + + writeMapfile(layers); + } + + + /** + * Returns the VelocityEngine used for the template mechanism. + * + * @return the velocity engine. + */ + protected VelocityEngine getVelocityEngine() { + if (velocityEngine == null) { + velocityEngine = new VelocityEngine(); + try { + setupVelocity(velocityEngine); + } + catch (Exception e) { + logger.error(e, e); + return null; + } + } + return velocityEngine; + } + + + /** + * Initialize velocity. + * + * @param engine Velocity engine. + * @throws Exception if an error occured while initializing velocity. + */ + protected void setupVelocity(VelocityEngine engine) + throws Exception + { + engine.setProperty( + "input.encoding", + "UTF-8"); + + engine.setProperty( + VelocityEngine.RUNTIME_LOG, + FLYSUtils.getXPathString(FLYSUtils.XPATH_VELOCITY_LOGFILE)); + + engine.setProperty( + "resource.loader", + "file"); + + engine.setProperty( + "file.resource.loader.path", + FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_TEMPLATE_PATH)); + + engine.init(); + } + + + protected VelocityContext getVelocityContext() { + VelocityContext context = new VelocityContext(); + + try { + context.put("MAPSERVERURL", + FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPSERVER_URL)); + context.put("SHAPEFILEPATH", + getShapefileBaseDir().getCanonicalPath()); + context.put("CONFIGDIR", + Config.getConfigDirectory().getCanonicalPath()); + } + catch (FileNotFoundException fnfe) { + // this is bad + } + catch (IOException ioe) { + // this is also bad + } + + return context; + } + + + /** + * Returns a template specified by <i>model</i>. + * + * @param model The name of the template. + * @return a template. + */ + protected Template getTemplateByName(String model) { + if (model.indexOf(".vm") < 0) { + model = model.concat(".vm"); + } + + try { + VelocityEngine engine = getVelocityEngine(); + if (engine == null) { + logger.error("Error while fetching VelocityEngine."); + return null; + } + + return engine.getTemplate(model); + } + catch (Exception e) { + logger.warn(e, e); + } + + return null; + } + + + /** + * Returns the mapfile template. + * + * @return the mapfile template. + * @throws Exception if an error occured while reading the configuration. + */ + protected Template getMapfileTemplate() + throws Exception + { + String mapfileName = FLYSUtils.getXPathString( + FLYSUtils.XPATH_MAPFILE_TEMPLATE); + + return getTemplateByName(mapfileName); + } + + + /** + * Returns the base directory storing the shapefiles. + * + * @return the shapefile base directory. + * + * @throws FileNotFoundException if no shapefile path is found or + * configured. + */ + public File getShapefileBaseDir() + throws FileNotFoundException, IOException + { + if (shapefileDirectory == null) { + String path = FLYSUtils.getXPathString( + FLYSUtils.XPATH_SHAPEFILE_DIR); + + if (path != null) { + shapefileDirectory = new File(path); + } + + if (shapefileDirectory == null) { + throw new FileNotFoundException("No shapefile directory given"); + } + + if (!shapefileDirectory.exists()) { + shapefileDirectory.mkdirs(); + } + } + + return shapefileDirectory; + } + + + protected File[] getUserDirs() + throws FileNotFoundException, IOException + { + File baseDir = getShapefileBaseDir(); + File[] artifactDirs = baseDir.listFiles(); + + // TODO ONLY RETURN DIRECTORIES OF THE SPECIFIED USER + + return artifactDirs; + } + + + + protected List<String> parseLayers(File[] dirs) { + List<String> layers = new ArrayList<String>(); + + for (File dir: dirs) { + File[] layerFiles = dir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File directory, String name) { + return name.startsWith(MS_LAYER_PREFIX); + } + }); + + for (File layer: layerFiles) { + try { + layers.add(layer.getCanonicalPath()); + } + catch (IOException ioe) { + logger.warn(ioe, ioe); + } + } + } + + return layers; + } + + + /** + * Creates a layer file used for Mapserver's mapfile which represents the + * floodmap. + * + * @param flys The FLYSArtifact that owns <i>wms</i>. + * @param wms The WMSLayerFacet that contains information for the layer. + */ + public void createUeskLayer( + FLYSArtifact flys, + WSPLGENLayerFacet wms, + String style, + CallContext context + ) throws FileNotFoundException, IOException + { + logger.debug("createUeskLayer"); + + LayerInfo layerinfo = new LayerInfo(); + layerinfo.setName(MS_WSPLGEN_PREFIX + flys.identifier()); + layerinfo.setType("POLYGON"); + layerinfo.setDirectory(flys.identifier()); + layerinfo.setData(WSPLGEN_RESULT_SHAPE); + layerinfo.setTitle(Resources.getMsg(Resources.getLocale(context.getMeta()), + "floodmap.uesk", + "Floodmap")); + layerinfo.setStyle(style); + layerinfo.setSrid(wms.getSrid()); + + String name = MS_LAYER_PREFIX + wms.getName(); + + Template template = getTemplateByName(WSPLGEN_LAYER_TEMPLATE); + if (template == null) { + logger.warn("Template '" + WSPLGEN_LAYER_TEMPLATE + "' found."); + return; + } + + try { + File dir = new File(getShapefileBaseDir(), flys.identifier()); + writeLayer(layerinfo, dir, name, template); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + logger.warn("Unable to write layer: " + name); + } + } + + + /** + * Creates a layer file used for Mapserver's mapfile which represents the + * user defined barriers. + * + * @param flys The FLYSArtifact that owns <i>wms</i>. + * @param wms The WMSLayerFacet that contains information for the layer. + */ + public void createBarriersLayer(FLYSArtifact flys, WMSLayerFacet wms) + throws FileNotFoundException, IOException + { + logger.debug("createBarriersLayer"); + + //String uuid = flys.identifier(); + //File dir = new File(getShapefileBaseDir(), uuid); + + createBarriersLineLayer(flys, wms); + createBarriersPolygonLayer(flys, wms); + } + + + protected void createBarriersLineLayer( + FLYSArtifact flys, + WMSLayerFacet wms + ) + throws FileNotFoundException, IOException + { + String uuid = flys.identifier(); + String group = MS_BARRIERS_PREFIX + uuid; + String groupTitle = "I18N_BARRIERS_TITLE"; + + File dir = new File(getShapefileBaseDir(), uuid); + File test = new File(dir, WSPLGEN_LINES_SHAPE); + + if (!test.exists() || !test.canRead()) { + logger.debug("No barrier line layer existing."); + return; + } + + LayerInfo lineInfo = new LayerInfo(); + lineInfo.setName(MS_LINE_PREFIX + uuid); + lineInfo.setType("LINE"); + lineInfo.setDirectory(uuid); + lineInfo.setData(WSPLGEN_LINES_SHAPE); + lineInfo.setTitle("I18N_LINE_SHAPE"); + lineInfo.setGroup(group); + lineInfo.setGroupTitle(groupTitle); + lineInfo.setSrid(wms.getSrid()); + + String nameLines = MS_LAYER_PREFIX + wms.getName() + "-lines"; + + Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); + if (tpl == null) { + logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); + return; + } + + try { + writeLayer(lineInfo, dir, nameLines, tpl); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + logger.warn("Unable to write layer: " + nameLines); + } + } + + + protected void createBarriersPolygonLayer( + FLYSArtifact flys, + WMSLayerFacet wms + ) + throws FileNotFoundException, IOException + { + String uuid = flys.identifier(); + String group = uuid + MS_BARRIERS_PREFIX; + String groupTitle = "I18N_BARRIERS_TITLE"; + + File dir = new File(getShapefileBaseDir(), uuid); + File test = new File(dir, WSPLGEN_POLYGONS_SHAPE); + + if (!test.exists() || !test.canRead()) { + logger.debug("No barrier line layer existing."); + return; + } + + LayerInfo polygonInfo = new LayerInfo(); + polygonInfo.setName(MS_POLYGONS_PREFIX + uuid); + polygonInfo.setType("POLYGON"); + polygonInfo.setDirectory(uuid); + polygonInfo.setData(WSPLGEN_POLYGONS_SHAPE); + polygonInfo.setTitle("I18N_POLYGON_SHAPE"); + polygonInfo.setGroup(group); + polygonInfo.setGroupTitle(groupTitle); + polygonInfo.setSrid(wms.getSrid()); + + String namePolygons = MS_LAYER_PREFIX + wms.getName() + "-polygons"; + + Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); + if (tpl == null) { + logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); + return; + } + + try { + writeLayer(polygonInfo, dir, namePolygons, tpl); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + logger.warn("Unable to write layer: " + namePolygons); + } + } + + + /** + * Creates a layer file used for Mapserver's mapfile which represents the + * shape files uploaded by the user. + * + * @param flys The FLYSArtifact that owns <i>wms</i>. + * @param wms The WMSLayerFacet that contains information for the layer. + */ + public void createUserShapeLayer(FLYSArtifact flys, WMSLayerFacet wms) + throws FileNotFoundException, IOException + { + logger.debug("createUserShapeLayer"); + + String uuid = flys.identifier(); + File dir = new File(getShapefileBaseDir(), uuid); + File test = new File(dir, WSPLGEN_USER_SHAPE); + + if (!test.exists() || !test.canRead()) { + logger.debug("No user layer existing."); + return; + } + + File userShape = new File(dir, WSPLGEN_USER_SHAPE); + ShpFiles sf = new ShpFiles(userShape); + ShapefileReader sfr = new ShapefileReader(sf, true, false, null); + ShapefileHeader sfh = sfr.getHeader(); + + String group = uuid + MS_USERSHAPE_PREFIX; + String groupTitle = "I18N_USER_SHAPE_TITLE"; + + LayerInfo info = new LayerInfo(); + info.setName(MS_USERSHAPE_PREFIX + uuid); + if (sfh.getShapeType().isLineType()) { + info.setType("LINE"); + } + else if (sfh.getShapeType().isPolygonType()) { + info.setType("POLYGON"); + } + else { + return; + } + info.setDirectory(uuid); + info.setData(WSPLGEN_USER_SHAPE); + info.setTitle("I18N_USER_SHAPE"); + info.setGroup(group); + info.setGroupTitle(groupTitle); + info.setSrid(wms.getSrid()); + + String nameUser = MS_LAYER_PREFIX + wms.getName(); + + Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); + if (tpl == null) { + logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found."); + return; + } + + try { + writeLayer(info, dir, nameUser, tpl); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + logger.warn("Unable to write layer: " + nameUser); + } + + } + + + /** + * Creates a layer file used for Mapserver's mapfile which represents + * geometries from database. + * + * @param flys The FLYSArtifact that owns <i>wms</i>. + * @param wms The WMSLayerFacet that contains information for the layer. + */ + public void createDatabaseLayer( + FLYSArtifact flys, + WMSDBLayerFacet wms, + String style + ) + throws FileNotFoundException, IOException + { + logger.debug("createDatabaseLayer"); + + LayerInfo layerinfo = new LayerInfo(); + layerinfo.setName(wms.getName() + "-" + flys.identifier()); + layerinfo.setType(wms.getGeometryType()); + layerinfo.setFilter(wms.getFilter()); + layerinfo.setData(wms.getData()); + layerinfo.setTitle(wms.getDescription()); + layerinfo.setStyle(style); + if(wms.getExtent() != null) { + layerinfo.setExtent(GeometryUtils.jtsBoundsToOLBounds(wms.getExtent())); + } + layerinfo.setConnection(wms.getConnection()); + layerinfo.setConnectionType(wms.getConnectionType()); + layerinfo.setLabelItem(wms.getLabelItem()); + layerinfo.setSrid(wms.getSrid()); + + String name = MS_LAYER_PREFIX + wms.getName(); + + Template template = getTemplateByName(DB_LAYER_TEMPLATE); + if (template == null) { + logger.warn("Template '" + DB_LAYER_TEMPLATE + "' found."); + return; + } + + try { + File dir = new File(getShapefileBaseDir(), flys.identifier()); + writeLayer(layerinfo, dir, name, template); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + logger.warn("Unable to write layer: " + name); + } + } + + + /** + * Creates a layer snippet which might be included in the mapfile. + * + * @param layerinfo A LayerInfo object that contains all necessary + * information to build a Mapserver LAYER section. + * @param dir The base dir for the LAYER snippet. + * @param filename The name of the file that is written. + * @param tpl The Velocity template which is used to create the LAYER + * section. + */ + protected void writeLayer( + LayerInfo layerinfo, + File dir, + String filename, + Template tpl + ) + throws FileNotFoundException + { + if (logger.isDebugEnabled()) { + logger.debug("Write layer for:"); + logger.debug(" directory: " + dir.getName()); + logger.debug(" name: " + filename); + } + + File layer = new File(dir, filename); + Writer writer = null; + + try { + writer = new FileWriter(layer); + + VelocityContext context = getVelocityContext(); + context.put("LAYER", layerinfo); + + tpl.merge(context, writer); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + catch (Exception e) { + logger.error(e, e); + } + finally { + try { + if (writer != null) { + writer.close(); + } + } + catch (IOException ioe) { + logger.debug(ioe, ioe); + } + } + } + + + /** + * Creates a mapfile with the layer information stored in <i>layers</i>. + * + * @param layers Layer information. + */ + protected void writeMapfile(List<String> layers) { + String tmpMapName = "mapfile" + new Date().getTime(); + + File mapfile = new File( + FLYSUtils.getXPathString(FLYSUtils.XPATH_MAPFILE_PATH)); + + File tmp = null; + Writer writer = null; + + try { + tmp = new File(mapfile.getParent(), tmpMapName); + tmp.createNewFile(); + + writer = new FileWriter(tmp); + + VelocityContext context = getVelocityContext(); + context.put("LAYERS", layers); + + Template mapTemplate = getMapfileTemplate(); + if (mapTemplate == null) { + logger.warn("No mapfile template found."); + return; + } + + mapTemplate.merge(context, writer); + + // we need to create a temporary mapfile first und rename it into + // real mapfile because we don't run into race conditions on this + // way. (iw) + tmp.renameTo(mapfile); + } + catch (FileNotFoundException fnfe) { + logger.error(fnfe, fnfe); + } + catch (IOException ioe) { + logger.error(ioe, ioe); + } + catch (Exception e) { + logger.error(e, e); + } + finally { + try { + if (writer != null) { + writer.close(); + } + + if (tmp.exists()) { + tmp.delete(); + } + } + catch (IOException ioe) { + logger.debug(ioe, ioe); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/Pair.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ + +package de.intevation.flys.utils; + +import java.io.Serializable; + +/** + * @param <A> + * @param <B> + * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> + */ +public final class Pair<A, B> +implements Serializable +{ + private A a; + private B b; + + private Pair() { + } + + public Pair(A a, B b) { + this.a = a; + this.b = b; + } + + public A getA() { + return a; + } + + public B getB() { + return b; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/ThemeUtil.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,710 @@ +package de.intevation.flys.utils; + +import java.awt.Color; +import java.awt.Font; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import de.intevation.artifacts.common.utils.XMLUtils; +import de.intevation.flys.artifacts.model.MapserverStyle; +import de.intevation.flys.artifacts.model.MapserverStyle.Clazz; +import de.intevation.flys.artifacts.model.MapserverStyle.Expression; +import de.intevation.flys.artifacts.model.MapserverStyle.Label; +import de.intevation.flys.artifacts.model.MapserverStyle.Style; + + +/** + * Utility to deal with themes and their representations. + */ +public class ThemeUtil { + + /** Private logger. */ + private static Logger logger = + Logger.getLogger(ThemeUtil.class); + + public final static String XPATH_FILL_COLOR = + "/theme/field[@name='fillcolor']/@default"; + + public final static String XPATH_LINE_COLOR = + "/theme/field[@name='linecolor']/@default"; + + public static final String XPATH_LINE_SIZE = + "/theme/field[@name='linesize']/@default"; + + public static final String XPATH_LINE_STYLE = + "/theme/field[@name='linetype']/@default"; + + public static final String XPATH_POINT_SIZE = + "/theme/field[@name='pointsize']/@default"; + + public static final String XPATH_POINT_COLOR = + "/theme/field[@name='pointcolor']/@default"; + + public final static String XPATH_SHOW_BORDER = + "/theme/field[@name='showborder']/@default"; + + public final static String XPATH_SHOW_POINTS = + "/theme/field[@name='showpoints']/@default"; + + public final static String XPATH_SHOW_LINE = + "/theme/field[@name='showlines']/@default"; + + public final static String XPATH_SHOW_VERTICAL_LINE = + "/theme/field[@name='showverticalline']/@default"; + + public final static String XPATH_SHOW_HORIZONTAL_LINE = + "/theme/field[@name='showhorizontalline']/@default"; + + public final static String XPATH_SHOW_LINE_LABEL = + "/theme/field[@name='showlinelabel']/@default"; + + public final static String XPATH_SHOW_POINT_LABEL = + "/theme/field[@name='showpointlabel']/@default"; + + public final static String XPATH_SHOW_WIDTH = + "/theme/field[@name='showwidth']/@default"; + + public final static String XPATH_SHOW_LEVEL = + "/theme/field[@name='showlevel']/@default"; + + public final static String XPATH_TRANSPARENT = + "/theme/field[@name='transparent']/@default"; + + public final static String XPATH_TRANSPARENCY = + "/theme/field[@name='transparency']/@default"; + + public final static String XPATH_SHOW_AREA = + "/theme/field[@name='showarea']/@default"; + + public final static String XPATH_SHOW_MIDDLE_HEIGHT = + "/theme/field[@name='showmiddleheight']/@default"; + + public final static String XPATH_LABEL_FONT_COLOR = + "/theme/field[@name='labelfontcolor']/@default"; + + public final static String XPATH_LABEL_FONT_SIZE = + "/theme/field[@name='labelfontsize']/@default"; + + public final static String XPATH_LABEL_FONT_FACE = + "/theme/field[@name='labelfontface']/@default"; + + public final static String XPATH_LABEL_FONT_STYLE = + "/theme/field[@name='labelfontstyle']/@default"; + + public final static String XPATH_TEXT_ORIENTATION = + "/theme/field[@name='textorientation']/@default"; + + public final static String XPATH_LABEL_BGCOLOR = + "/theme/field[@name='labelbgcolor']/@default"; + + public final static String XPATH_LABEL_SHOW_BACKGROUND = + "/theme/field[@name='labelshowbg']/@default"; + + public final static String XPATH_BACKGROUND_COLOR = + "/theme/field[@name='backgroundcolor']/@default"; + + public final static String XPATH_SYMBOL = + "/theme/field[@name='symbol']/@default"; + + public final static String XPATH_SHOW_MINIMUM = + "/theme/field[@name='showminimum']/@default"; + + public final static String XPATH_SHOW_MAXIMUM = + "/theme/field[@name='showmaximum']/@default"; + + public final static String XPATH_WSPLGEN_FIELDS = + "/theme[@name='WSPLGEN']/field"; + + /** XPATH to bandwidth field. */ + public final static String XPATH_BANDWIDTH = + "/theme/field[@name='bandwidth']/@default"; + + + /** Parse string to be boolean with default if empty or unrecognized. */ + public static boolean parseBoolean(String value, boolean defaultsTo) { + if (value == null || value.length() == 0) { + return defaultsTo; + } + if (value.equals("false")) { + return false; + } + else if (value.equals("true")) { + return true; + } + else { + return defaultsTo; + } + } + + + /** + * Attempt converting \param value to an integer, in failing cases, + * return \param defaultsTo. + * @param value String to be converted to integer. + * @param defaultsTo Default to return if conversion failed. + * @return \param value as integer or defaultsto if conversion failed. + */ + public static int parseInteger(String value, int defaultsTo) { + if (value == null || value.length() == 0) { + return defaultsTo; + } + + try { + return Integer.parseInt(value); + } + catch (NumberFormatException nfe) { + // do nothing + } + + return defaultsTo; + } + + + /** + * Attempt converting \param value to a double, in failing cases, + * return \param defaultsTo. + * @param value String to be converted to double. + * @param defaultsTo Default to return if conversion failed. + * @return \param value as integer or defaultsto if conversion failed. + */ + public static double parseDouble(String value, double defaultsTo) { + if (value == null || value.length() == 0) { + return defaultsTo; + } + + try { + return Double.parseDouble(value); + } + catch (NumberFormatException nfe) { + // do nothing + } + + return defaultsTo; + } + + + /** + * Parses line width, defaulting to 0. + * @param theme the theme + */ + public static int parseLineWidth(Document theme) { + String size = XMLUtils.xpathString(theme, XPATH_LINE_SIZE, null); + if (size == null || size.length() == 0) { + return 0; + } + + try { + return Integer.parseInt(size); + } + catch (NumberFormatException nfe) { + logger.warn("Unable to set line size from string: '" + size + "'"); + } + return 0; + } + + + /** + * Parse band width, defaulting to 0. + * @param theme the theme. + */ + public static double parseBandWidth(Document theme) { + String bandWidth = XMLUtils.xpathString(theme, XPATH_BANDWIDTH, null); + + return parseDouble(bandWidth, 0); + } + + + public static int parsePointWidth(Document theme) { + String width = XMLUtils.xpathString(theme, XPATH_POINT_SIZE, null); + + return parseInteger(width, 3); + } + + + public static Color parsePointColor(Document theme) { + String color = XMLUtils.xpathString(theme, XPATH_POINT_COLOR, null); + logger.debug("parsePointColor(): color = " + color); + return parseColor(color); + } + + + /** + * Parses the line style, defaulting to '10'. + * @param theme The theme. + */ + public static float[] parseLineStyle(Document theme) { + String dash = XMLUtils.xpathString(theme, XPATH_LINE_STYLE, null); + + float[] def = {10}; + if (dash == null || dash.length() == 0) { + return def; + } + + String[] pattern = dash.split(","); + if(pattern.length == 1) { + return def; + } + + try { + float[] dashes = new float[pattern.length]; + for (int i = 0; i < pattern.length; i++) { + dashes[i] = Float.parseFloat(pattern[i]); + } + return dashes; + } + catch(NumberFormatException nfe) { + logger.warn("Unable to set dash from string: '" + dash + "'"); + return def; + } + } + + + /** + * Parses text size, defaulting to 10. + * @param theme The theme. + */ + public static int parseTextSize(Document theme, String path) { + String size = XMLUtils.xpathString(theme, path, null); + if (size == null || size.length() == 0) { + return 10; + } + + try { + return Integer.parseInt(size); + } + catch (NumberFormatException nfe) { + } + return 10; + } + + + public static int parseTextSize(Document theme) { + return parseTextSize(theme, XPATH_LABEL_FONT_SIZE); + } + + + /** + * Parses the attribute 'showpoints', defaults to false. + * @param theme The theme. + */ + public static boolean parseShowPoints(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_POINTS, null); + return parseBoolean(show, false); + } + + /** + * Parses the attribute 'showmiddleheight', defaults to false. + * @param theme The theme. + */ + public static boolean parseShowMiddleHeight(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_MIDDLE_HEIGHT, null); + return parseBoolean(show, false); + } + + /** + * Parses the attribute 'showarea', defaults to false. + * @param theme The theme. + */ + public static boolean parseShowArea(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_AREA, null); + return parseBoolean(show, false); + } + + /** + * Parses the attribute 'showverticalline', defaults to true. + * @param theme The theme. + */ + public static boolean parseShowVerticalLine(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_VERTICAL_LINE, null); + return parseBoolean(show, true); + } + + /** + * Parses the attribute 'showhorizontalline', defaults to true. + * @param theme The theme. + */ + public static boolean parseShowHorizontalLine(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_HORIZONTAL_LINE, null); + return parseBoolean(show, true); + } + + /** + * Parses the attribute 'showlines', defaults to true. + * @param theme The theme. + */ + public static boolean parseShowLine(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_LINE, null); + return parseBoolean(show, true); + } + + /** + * Parses the attribute 'showlinelabel', defaults to true. + * @param theme The theme. + */ + public static boolean parseShowLineLabel(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_LINE_LABEL, null); + return parseBoolean(show, false); + } + + public static boolean parseShowPointLabel(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_POINT_LABEL, null); + return parseBoolean(show, false); + } + + /** + * Parses text color. + * @param theme The theme. + */ + public static Color parseTextColor(Document theme) { + return parseRGB(getTextColorString(theme)); + } + + + /** + * Parses the font. + * @param theme The theme. + */ + public static Font parseTextFont(Document theme) { + String font = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_FACE, null); + if (font == null || font.length() == 0) { + return null; + } + + int size = parseTextSize(theme); + int style = parseTextStyle(theme); + Font f = new Font (font, style, size); + return f; + } + + + /** + * Parses the text style, defaults to 'Font.PLAIN'. + * @param theme The theme. + */ + public static int parseTextStyle(Document theme, String path) { + String style = XMLUtils.xpathString(theme, path, null); + if (style == null || style.length() == 0) { + return Font.PLAIN; + } + + if (style.equals("italic")) { + return Font.ITALIC; + } + else if (style.equals("bold")) { + return Font.BOLD; + } + else { + return Font.PLAIN; + } + } + + + public static int parseTextStyle(Document theme) { + return parseTextStyle(theme, XPATH_LABEL_FONT_STYLE); + } + + + public static boolean parseShowWidth(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_WIDTH, null); + return parseBoolean(show, false); + } + + + public static boolean parseShowLevel(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_SHOW_LEVEL, null); + return parseBoolean(show, false); + } + + /** + * Parses the textorientation, defaults to 'vertical'. + * @param theme The theme. + */ + public static String parseTextOrientation(Document theme) { + String o = XMLUtils.xpathString(theme, XPATH_TEXT_ORIENTATION, null); + if ("true".equals(o)) { + return "horizontal"; + } + else { + return "vertical"; + } + } + + + /** + * Parses the text background color, defaults to white. + * @param theme The theme. + */ + public static Color parseTextBackground(Document theme) { + String color = getLabelBackgroundColorString(theme); + if (color == null || color.length() == 0) { + return Color.WHITE; + } + return parseRGB(color); + } + + + /** + * Parses the attribute whether to show background or not, defaults to + * false. + * @param theme The theme. + */ + public static boolean parseLabelShowBackground(Document theme) { + String show = XMLUtils.xpathString(theme, XPATH_LABEL_SHOW_BACKGROUND, null); + return parseBoolean(show, false); + } + + + public static Color parseColor(String colorString) { + if (colorString == null || colorString.length() == 0) { + return null; + } + else if (colorString.indexOf("#") == 0) { + return parseHexColor(colorString); + } + else if (colorString.indexOf(",") >= 0) { + return parseRGB(colorString); + } + + return null; + } + + + /** + * Parse a string like "#00CC22" and return the corresponding color. + * + * @param hex The hex color value. + * + * @return a Color or null, if <i>hex</i> is empty. + */ + public static Color parseHexColor(String hex) { + if (hex == null) { + return null; + } + + return Color.decode(hex); + } + + /** + * Parse a string like "103, 100, 0" and return a corresping color. + * @param rgbtext Color as string representation, e.g. "255,0,20". + * @return Color, null in case of issues. + */ + public static Color parseRGB(String rgbtext) { + if (rgbtext == null) { + return null; + } + String rgb[] = rgbtext.split(","); + Color c = null; + try { + c = new Color( + Integer.parseInt(rgb[0].trim()), + Integer.parseInt(rgb[1].trim()), + Integer.parseInt(rgb[2].trim())); + } + catch (NumberFormatException nfe) { + c = null; + } + return c; + } + + + public static String getLineColorString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_LINE_COLOR, null); + } + + + /** Get show border as string. */ + public static String getShowBorderString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_SHOW_BORDER, null); + } + + + /** Get fill color as string. */ + public static String getFillColorString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_FILL_COLOR, null); + } + + + public static String getLabelBackgroundColorString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_LABEL_BGCOLOR, null); + } + + + public static String getBackgroundColorString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_BACKGROUND_COLOR, null); + } + + + public static String getTextColorString(Document theme) { + String textColor = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_COLOR, null); + return textColor; + } + + + public static String getSymbol(Document theme) { + return XMLUtils.xpathString(theme, XPATH_SYMBOL, null); + } + + + public static String getTransparencyString(Document theme) { + return XMLUtils.xpathString(theme, XPATH_TRANSPARENCY, null); + } + + + public static String getTransparency(Document theme) { + return XMLUtils.xpathString(theme, XPATH_TRANSPARENCY, null); + } + + + public static String getShowMinimum(Document theme) { + return XMLUtils.xpathString(theme, XPATH_SHOW_MINIMUM, null); + } + + + public static String getShowMaximum(Document theme) { + return XMLUtils.xpathString(theme, XPATH_SHOW_MAXIMUM, null); + } + + + /** + * Gets color from color field. + * @param theme the theme document. + * @return color. + */ + public static Color parseFillColorField(Document theme) { + return parseRGB(getFillColorString(theme)); + } + + + public static boolean parseShowBorder(Document theme) { + return parseBoolean(getShowBorderString(theme), false); + } + + + public static boolean parseTransparency(Document theme) { + return parseBoolean(getTransparencyString(theme), false); + } + + + /** + * Gets color from color field. + * @param theme the theme document. + * @return color. + */ + public static Color parseLineColorField(Document theme) { + String lineColorStr = getLineColorString(theme); + logger.debug("parseLineColorField: lineColorStr = " + + (lineColorStr == null ? "null" : lineColorStr)); + return parseRGB(lineColorStr); + } + + + public static boolean parseShowMinimum(Document theme) { + return parseBoolean(getShowMinimum(theme), false); + } + + + public static boolean parseShowMaximum(Document theme) { + return parseBoolean(getShowMaximum(theme), false); + } + + + public static String createWSPLGENStyle(Document theme) { + NodeList categories = (NodeList) XMLUtils.xpath( + theme, + XPATH_WSPLGEN_FIELDS, + XPathConstants.NODESET); + + return createWSPLGENStyle(categories).toString(); + } + + protected static MapserverStyle createWSPLGENStyle(NodeList categories) { + MapserverStyle ms = new MapserverStyle(); + + for (int i = 0, n = categories.getLength(); i < n; i++) { + Element cat = (Element) categories.item(i); + String color = cat.getAttribute("default"); + String name = cat.getAttribute("name"); + + String expr; + + try { + int length = name.length(); + int idx = Integer.parseInt(name.substring(length-1, length)); + + expr = createWSPLGENExpression(idx); + } + catch (NumberFormatException nfe) { + logger.warn("Error while parsing WSPLGEN category.", nfe); + continue; + } + + Clazz c = new Clazz(expr); + Style s = new Style(); + s.setColor(color.replace(",", "")); + s.setSize(5); + + c.addItem(new Expression("(" + expr + ")")); + c.addItem(s); + + ms.addClazz(c); + } + + return ms; + } + + + protected static String createWSPLGENExpression(int idx) { + if (idx < 5) { + int lower = idx - 1; + return "[DIFF] >= " + lower + " AND [DIFF] < " + idx; + } + else { + return "[DIFF] >= 4"; + } + } + + + public static String createMapserverStyle(Document theme) { + String symbol = getSymbol(theme); + String backcolor = getLabelBackgroundColorString(theme); + String linecolor = getLineColorString(theme); + + int linewidth = parseLineWidth(theme); + + MapserverStyle ms = new MapserverStyle(); + + Clazz c = new Clazz(" "); + + Style s = new Style(); + s.setOutlineColor(linecolor.replace(",", "")); + + if (backcolor != null && backcolor.length() > 0) { + s.setColor(backcolor.replace(",", "")); + } + + s.setSize(linewidth); + s.setSymbol(symbol); + c.addItem(s); + + String textcolor = getTextColorString(theme); + int textsize = parseTextSize(theme); + + if (textcolor != null && textcolor.length() > 0 && textsize > 0) { + Label l = new Label(); + l.setColor(textcolor.replace(",", "")); + l.setSize(textsize); + c.addItem(l); + } + + ms.addClazz(c); + + return ms.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/FacetCreator.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,186 @@ +package de.intevation.flys.wsplgen; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.map.WMSLayerFacet; +import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet; +import de.intevation.flys.artifacts.resources.Resources; +import de.intevation.flys.artifacts.states.DefaultState.ComputeType; +import de.intevation.flys.model.CrossSectionTrack; +import de.intevation.flys.utils.FLYSUtils; +import de.intevation.flys.utils.GeometryUtils; +import de.intevation.flys.utils.MapfileGenerator; + + +public class FacetCreator implements FacetTypes { + + public static final String I18N_WSPLGEN_RESULT = "floodmap.uesk"; + public static final String I18N_WSPLGEN_DEFAULT = "floodmap.uesk"; + public static final String I18N_BARRIERS = "floodmap.barriers"; + public static final String I18N_BARRIERS_DEFAULT = "floodmap.barriers"; + public static final String I18N_USERSHAPE = "floodmap.usershape"; + public static final String I18N_USERSHAPE_DEFAULT = "floodmap.usershape"; + + protected FLYSArtifact artifact; + + protected CallContext cc; + + protected List<Facet> facets; + protected List<Facet> tmpFacets; + + protected String url; + protected String hash; + protected String stateId; + + + private static Logger logger = Logger.getLogger(FacetCreator.class); + + + public FacetCreator( + FLYSArtifact artifact, + CallContext cc, + String hash, + String sId, + List<Facet> facets + ) { + this.tmpFacets = new ArrayList<Facet>(2); + this.facets = facets; + this.artifact = artifact; + this.cc = cc; + this.hash = hash; + this.stateId = sId; + } + + protected String getRiver() { + return artifact.getDataAsString("river"); + } + + protected String getUrl() { + return FLYSUtils.getUserWMSUrl(artifact.identifier()); + } + + protected String getSrid() { + return FLYSUtils.getRiverSrid(artifact); + } + + protected Envelope getWSPLGENBounds() { + String river = getRiver(); + double kms[] = FLYSUtils.getKmRange(artifact); + + logger.debug("### getWSPLGENBounds"); + logger.debug("### from km: " + kms[0]); + logger.debug("### to km: " + kms[1]); + + CrossSectionTrack a = + CrossSectionTrack.getCrossSectionTrack(river, kms[0]); + + CrossSectionTrack b = + CrossSectionTrack.getCrossSectionTrack(river, kms[1]); + + if (a == null || b == null) { + return null; + } + + Envelope envA = a.getGeom().getEnvelopeInternal(); + Envelope envB = b.getGeom().getEnvelopeInternal(); + + envA.expandToInclude(envB); + + logger.debug("### => " + envA); + + return envA; + } + + protected Envelope getBounds() { + return GeometryUtils.getRiverBoundary(getRiver()); + } + + public List<Facet> getFacets() { + return tmpFacets; + } + + public void createWSPLGENFacet() { + WSPLGENLayerFacet wsplgen = new WSPLGENLayerFacet( + 0, + FLOODMAP_WSPLGEN, + Resources.getMsg( + cc.getMeta(), + I18N_WSPLGEN_RESULT, + I18N_WSPLGEN_DEFAULT), + ComputeType.ADVANCE, + stateId, + hash, + getUrl()); + + Envelope bounds = getWSPLGENBounds(); + + if (bounds == null) { + bounds = getBounds(); + } + + wsplgen.addLayer( + MapfileGenerator.MS_WSPLGEN_PREFIX + artifact.identifier()); + wsplgen.setSrid(getSrid()); + wsplgen.setExtent(bounds); + + tmpFacets.add(wsplgen); + } + + public void createBarrierFacet() { + WMSLayerFacet barriers = new WMSLayerFacet( + 1, + FLOODMAP_BARRIERS, + Resources.getMsg( + cc.getMeta(), + I18N_BARRIERS, + I18N_BARRIERS_DEFAULT), + ComputeType.ADVANCE, + stateId, + hash, + getUrl()); + + barriers.addLayer( + MapfileGenerator.MS_BARRIERS_PREFIX + artifact.identifier()); + barriers.setSrid(getSrid()); + barriers.setExtent(getBounds()); + + tmpFacets.add(barriers); + } + + + public void createUserShapeFacet() { + WMSLayerFacet shape = new WMSLayerFacet( + 1, + FLOODMAP_USERSHAPE, + Resources.getMsg( + cc.getMeta(), + I18N_USERSHAPE, + I18N_USERSHAPE_DEFAULT), + ComputeType.ADVANCE, + stateId, + hash, + getUrl()); + + shape.addLayer( + MapfileGenerator.MS_USERSHAPE_PREFIX + artifact.identifier()); + shape.setSrid(getSrid()); + shape.setExtent(getBounds()); + + tmpFacets.add(shape); + } + + + public void finish() { + facets.addAll(getFacets()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/JobObserver.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,106 @@ +package de.intevation.flys.wsplgen; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.model.CalculationMessage; +import de.intevation.flys.artifacts.model.map.WSPLGENJob; + + +public class JobObserver extends Thread { + + private static Logger logger = Logger.getLogger(JobObserver.class); + + + public static final String WSPLGEN_ENCODING = + "ISO-8859-1"; + + public static final String WSPLGEN_LOG_OUTPUT = + System.getProperty("wsplgen.log.output", "false"); + + public static final String[] STEPS = { + ".*<-Auswertung der Kommandozeilen-Parameter beendet.*", + ".*->Laden des DGM in Datei '.*' gestartet.*", + ".*->Triangulierung der Knoten gestartet.*", + ".*->Anpassung der Elemente an Dämme und Gräben gestartet.*", + ".*<-WSPLGEN Version .* beendet.*" + }; + + + protected WSPLGENJob job; + + protected InputStream in; + + protected Pattern[] patterns; + + protected int len; + + protected boolean copy; + + + public JobObserver(WSPLGENJob job) { + this.job = job; + this.len = 0; + this.copy = Boolean.parseBoolean(WSPLGEN_LOG_OUTPUT); + + patterns = new Pattern[STEPS.length]; + } + + + protected void prepareRegexes() { + for (int num = STEPS.length, i = 0; i < num; i++) { + patterns[i] = Pattern.compile(STEPS[i], Pattern.DOTALL); + } + } + + + public void setInputStream(InputStream in) { + this.in = in; + } + + + public void run() { + logger.debug("Start observation..."); + prepareRegexes(); + + try { + BufferedReader reader = + new BufferedReader( + new InputStreamReader(in, WSPLGEN_ENCODING)); + + String line = null; + + while ((line = reader.readLine()) != null) { + if (copy) { + logger.debug(line); + } + + update(line); + } + } + catch (IOException ioe) { + logger.warn("Observation canceled: " + ioe.getMessage()); + } + } + + + protected void update(String log) { + for (int num = patterns.length, i = 0; i < num; i++) { + Matcher m = patterns[i].matcher(log); + + if (m.matches()) { + job.getCallContext().addBackgroundMessage( + new CalculationMessage(num, i+1, log)); + + logger.info("Finished step " + (i+1) + " / " + num); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=5 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,115 @@ +package de.intevation.flys.wsplgen; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +import de.intevation.flys.artifacts.model.map.WSPLGENCalculation; +import de.intevation.flys.artifacts.model.map.WSPLGENJob; + + +public class ProblemObserver extends JobObserver { + + private static Logger logger = Logger.getLogger(ProblemObserver.class); + + + public static final Pattern WSPLGEN_ERROR_START = Pattern.compile( + ".*->(.*Fehler)(\\s*\\((\\d+)\\).*)*", + Pattern.DOTALL); + + public static final Pattern WSPLGEN_ERROR_END = Pattern.compile( + ".*<-(.*Fehler).*", + Pattern.DOTALL); + + public static final Pattern WSPLGEN_WARNING_START = Pattern.compile( + ".*->Warnung\\s*\\((\\d+)\\).*", + Pattern.DOTALL); + + public static final Pattern WSPLGEN_WARNING_END = Pattern.compile( + ".*<-Warnung .*", + Pattern.DOTALL); + + + protected int error; + protected int warning; + + protected WSPLGENCalculation calculation; + + + public ProblemObserver(WSPLGENJob job) { + super(job); + error = -1; + warning = -1; + calculation = job.getCalculation(); + } + + + public void run() { + logger.debug("Start observation..."); + + super.run(); + } + + + @Override + protected void prepareRegexes() { + // do nothing + } + + + @Override + protected void update(String log) { + Matcher startError = WSPLGEN_ERROR_START.matcher(log); + if (startError.matches()) { + if (startError.groupCount() >= 2) { + String tmp = startError.group(3); + + if (tmp != null && tmp.length() > 0) { + error = Integer.parseInt(tmp); + } + else error = 1; + } + else { + error = 1; + } + + return; + } + + Matcher endError = WSPLGEN_ERROR_END.matcher(log); + if (endError.matches()) { + error = -1; + } + + if (error > 0) { + calculation.addError(new Integer(error), log); + } + + Matcher startWarning = WSPLGEN_WARNING_START.matcher(log); + if (startWarning.matches()) { + warning = Integer.parseInt(startWarning.group(1)); + return; + } + + Matcher endWarning = WSPLGEN_WARNING_END.matcher(log); + if (endWarning.matches()) { + warning = -1; + } + + if (warning > 0) { + calculation.addWarning(new Integer(warning), log); + } + } + + + public int numErrors() { + return calculation.numErrors(); + } + + + public int numWarnings() { + return calculation.numWarnings(); + } +} +// vim:set ts=4 sw=4 si et sta sts=5 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/Scheduler.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,111 @@ +package de.intevation.flys.wsplgen; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledThreadPoolExecutor; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.model.map.WSPLGENJob; + + +/** + * The Scheduler is used to retrieve new WSPLGENJob. The incoming jobs are added + * to a ScheduledThreadPoolExecutor. This thread pool has a number of worker + * threads that processes the WSPLGENJobs. The number of worker threads can be + * set using a System property <i>wsplgen.max.threads</i> ; its default value is + * 1. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class Scheduler { + + private class FutureJob { + public Future future; + public WSPLGENJob job; + + public FutureJob(Future future, WSPLGENJob job) { + this.future = future; + this.job = job; + } + } + + public static final int MAX_WSPLGEN_PROCESSES = + Integer.getInteger("wsplgen.max.threads", 1); + + + protected ScheduledThreadPoolExecutor pool; + protected Map<String, FutureJob> jobs; + + + private static Scheduler INSTANCE; + + private static final Logger logger = Logger.getLogger(Scheduler.class); + + + + private Scheduler() { + jobs = new HashMap<String, FutureJob>(); + pool = new ScheduledThreadPoolExecutor(MAX_WSPLGEN_PROCESSES); + } + + + public static Scheduler getInstance() { + if (INSTANCE == null) { + logger.info("Create new WSPLGEN Scheduler..."); + + INSTANCE = new Scheduler(); + } + + return INSTANCE; + } + + + public void addJob(final WSPLGENJob job) { + synchronized (jobs) { + WSPLGENFuture f = new WSPLGENFuture(new WSPLGENCallable(this, job)); + pool.execute(f); + + jobs.put(job.getArtifact().identifier(), new FutureJob(f, job)); + + logger.info("New WSPLGEN job successfully added."); + } + } + + + /** + * Cancels a running (or queued) job. + * + * @param jobId The id of the job (which is the identifier of an Artifact). + */ + public void cancelJob(String jobId) { + logger.debug("Search job in queue: " + jobId); + + synchronized (jobs) { + FutureJob fj = jobs.get(jobId); + + if (fj != null) { + logger.info("Try to cancel job: " + jobId); + + fj.future.cancel(true); + + removeJob(jobId); + + fj.job.getCallContext().afterBackground( + CallContext.STORE); + + logger.info("Canceled job: " + jobId); + } + } + } + + + protected void removeJob(String id) { + synchronized (jobs) { + jobs.remove(id); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/SchedulerSetup.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,37 @@ +package de.intevation.flys.wsplgen; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifactdatabase.LifetimeListener; + +import de.intevation.flys.artifacts.context.FLYSContext; + + +/** + * A LifetimeListener that is used to create an instance of Scheduler. This + * instance is put into the GlobalContext using FLYSContext.SCHEDULER. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class SchedulerSetup implements LifetimeListener { + + @Override + public void setup(Document document) { + } + + + @Override + public void systemUp(GlobalContext globalContext) { + Scheduler scheduler = Scheduler.getInstance(); + globalContext.put(FLYSContext.SCHEDULER, scheduler); + } + + + @Override + public void systemDown(GlobalContext globalContext) { + // TODO IMPLEMENT ME! + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,139 @@ +package de.intevation.flys.wsplgen; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.Callable; + +import org.apache.log4j.Logger; + +import de.intevation.artifacts.CallContext; +import de.intevation.flys.artifacts.model.map.WSPLGENJob; + + +/** + * A Callable that is used to start and observe an external Process for WSPLGEN. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WSPLGENCallable implements Callable { + + public static final String WSPLGEN_PARAMETER_FILE = + "wsplgen.par"; + + public static final String WSPLGEN_BIN_PATH = + System.getProperty("wsplgen.bin.path"); + + + private Logger logger = Logger.getLogger(WSPLGENCallable.class); + + private Process process; + + protected Scheduler scheduler; + + protected WSPLGENJob job; + + protected JobObserver logObserver; + protected ProblemObserver errorObserver; + + + public WSPLGENCallable(Scheduler scheduler, WSPLGENJob job) { + this.scheduler = scheduler; + this.job = job; + this.logObserver = new JobObserver(job); + this.errorObserver = new ProblemObserver(job); + } + + + @Override + public WSPLGENJob call() { + File dir = job.getWorkingDir(); + File parameter = new File(dir, WSPLGEN_PARAMETER_FILE); + + String[] args = new String[] { + WSPLGEN_BIN_PATH, + "-PAR=\"" + parameter.getAbsolutePath() + "\"" + }; + + execute(args, dir); + + return job; + } + + + protected void execute(String[] args, File dir) { + logger.info("Start JobExecutor for artifact: " + dir.getName()); + + String errorMsg = null; + + try { + synchronized (this) { + process = Runtime.getRuntime().exec(args, null, dir); + + logObserver.setInputStream(process.getInputStream()); + errorObserver.setInputStream(process.getErrorStream()); + + logObserver.start(); + errorObserver.start(); + + try { + process.waitFor(); + } + catch (InterruptedException ie) { + logger.warn("WSPLGEN job interrupted: " + ie.getMessage()); + } + + try { + logObserver.join(); + errorObserver.join(); + } + catch (InterruptedException iee) { /* do nothing */ } + + logger.info("WSPLGEN exit value: " + process.exitValue()); + logger.info( + "WSPLGEN throw " + + errorObserver.numErrors() + " errors."); + logger.info( + "WSPLGEN throw " + + errorObserver.numWarnings() + " warnings."); + + if (process.exitValue() < 2 && errorObserver.numErrors() == 0) { + FacetCreator fc = job.getFacetCreator(); + fc.createWSPLGENFacet(); + fc.finish(); + } + + job.getCallContext().afterBackground(CallContext.STORE); + + scheduler.removeJob(getJob().getArtifact().identifier()); + + return; + } + } + catch (SecurityException se) { + logger.error(se); + } + catch (IOException ioe) { + logger.error(ioe); + } + catch (NullPointerException npe) { + logger.error(npe, npe); + } + catch (IndexOutOfBoundsException ioobe) { + logger.error(ioobe, ioobe); + } + } + + + public void cancelWSPLGEN() { + if (process != null) { + logger.debug("Cancel running WSPLGEN process."); + process.destroy(); + } + } + + + public WSPLGENJob getJob() { + return job; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/WSPLGENFuture.java Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,41 @@ +package de.intevation.flys.wsplgen; + +import java.util.concurrent.FutureTask; + +import org.apache.log4j.Logger; + + +/** + * This FutureTask overrides the <i>cancel()</i> method. Before super.cancel() + * is called, WSPLGENCallable.cancelWSPLGEN() is executed to kill a running + * WSPLGEN process. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class WSPLGENFuture extends FutureTask { + + private static final Logger logger = Logger.getLogger(WSPLGENFuture.class); + + protected WSPLGENCallable wsplgenCallable; + + + public WSPLGENFuture(WSPLGENCallable callable) { + super(callable); + this.wsplgenCallable = callable; + } + + + public WSPLGENCallable getWSPLGENCallable() { + return wsplgenCallable; + } + + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + logger.debug("WSPLGENFuture.cancel"); + + wsplgenCallable.cancelWSPLGEN(); + return super.cancel(mayInterruptIfRunning); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/datacage-sql/org-h2-driver.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,29 @@ +delete.all.users = DELETE FROM users +delete.all.artifacts = DELETE FROM artifacts +user.id.nextval = SELECT NEXTVAL('USERS_ID_SEQ') +user.by.gid = SELECT id FROM users WHERE gid = ? +insert.user = INSERT INTO users (id, gid) VALUES (?, ?) +collection.by.gid = SELECT id FROM collections WHERE gid = ? +collection.id.nextval = SELECT NEXTVAL('COLLECTIONS_ID_SEQ') +insert.collection = INSERT INTO collections (id, gid, user_id, name, creation) VALUES (?, ?, ?, ?, ?) +artifact.by.gid = SELECT id FROM artifacts WHERE gid = ? +collection.item.id.nextval = SELECT NEXTVAL('COLLECTION_ITEMS_ID_SEQ') +insert.collection.item = INSERT INTO collection_items (id, collection_id, artifact_id) VALUES (?, ?, ?) +artifact.id.nextval = SELECT NEXTVAL('ARTIFACTS_ID_SEQ') +insert.artifact = INSERT INTO artifacts (id, gid, state, creation) VALUES (?, ?, ?, ?) +artifact.data.id.nextval = SELECT NEXTVAL('ARTIFACT_DATA_ID_SEQ') +insert.artifact.data = INSERT INTO artifact_data (id, artifact_id, kind, k, v) VALUES (?, ?, ?, ?, ?) +out.id.nextval = SELECT NEXTVAL('OUTS_ID_SEQ') +insert.out = INSERT INTO outs (id, artifact_id, name, description, out_type) VALUES (?, ?, ?, ?, ?) +facet.id.nextval = SELECT NEXTVAL('FACETS_ID_SEQ') +insert.facet = INSERT INTO facets (id, out_id, name, num, state, description) VALUES (?, ?, ?, ?, ?, ?) + +update.collection.name = UPDATE collections SET name = ? WHERE gid = ? +delete.artifact.from.collection = DELETE FROM collection_items WHERE collection_id = ? AND artifact_id = ? +delete.collection.by.gid = DELETE FROM collections WHERE gid = ? +delete.user.by.gid = DELETE FROM user WHERE gid = ? +delete.artifact.data.by.artifact.id = DELETE FROM artifact_data WHERE artifact_id = ? +delete.outs.by.artifact.id = DELETE FROM outs WHERE artifact_id = ? +delete.facets.by.artifact.id = DELETE FROM facets WHERE out_id IN (SELECT id FROM outs WHERE artifact_id = ?) + +delete.artifact.by.gid = DELETE FROM artifacts WHERE gid = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/datacage-sql/org-postgresql-driver.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,29 @@ +delete.all.users = DELETE FROM users +delete.all.artifacts = DELETE FROM artifacts +user.id.nextval = SELECT NEXTVAL('USERS_ID_SEQ') +user.by.gid = SELECT id FROM users WHERE gid = ?::uuid +insert.user = INSERT INTO users (id, gid) VALUES (?, ?::uuid) +collection.by.gid = SELECT id FROM collections WHERE gid = ?::uuid +collection.id.nextval = SELECT NEXTVAL('COLLECTIONS_ID_SEQ') +insert.collection = INSERT INTO collections (id, gid, user_id, name, creation) VALUES (?, ?::uuid, ?, ?, ?) +artifact.by.gid = SELECT id FROM artifacts WHERE gid = ?::uuid +collection.item.id.nextval = SELECT NEXTVAL('COLLECTION_ITEMS_ID_SEQ') +insert.collection.item = INSERT INTO collection_items (id, collection_id, artifact_id) VALUES (?, ?, ?) +artifact.id.nextval = SELECT NEXTVAL('ARTIFACTS_ID_SEQ') +insert.artifact = INSERT INTO artifacts (id, gid, state, creation) VALUES (?, ?::uuid, ?, ?) +artifact.data.id.nextval = SELECT NEXTVAL('ARTIFACT_DATA_ID_SEQ') +insert.artifact.data = INSERT INTO artifact_data (id, artifact_id, kind, k, v) VALUES (?, ?, ?, ?, ?) +out.id.nextval = SELECT NEXTVAL('OUTS_ID_SEQ') +insert.out = INSERT INTO outs (id, artifact_id, name, description, out_type) VALUES (?, ?, ?, ?, ?) +facet.id.nextval = SELECT NEXTVAL('FACETS_ID_SEQ') +insert.facet = INSERT INTO facets (id, out_id, name, num, state, description) VALUES (?, ?, ?, ?, ?, ?) + +update.collection.name = UPDATE collections SET name = ? WHERE gid = ?::uuid +delete.artifact.from.collection = DELETE FROM collection_items WHERE collection_id = ? AND artifact_id = ? +delete.collection.by.gid = DELETE FROM collections WHERE gid = ?::uuid +delete.user.by.gid = DELETE FROM user WHERE gid = ?::uuid +delete.artifact.data.by.artifact.id = DELETE FROM artifact_data WHERE artifact_id = ? +delete.outs.by.artifact.id = DELETE FROM outs WHERE artifact_id = ? +delete.facets.by.artifact.id = DELETE FROM facets WHERE out_id IN (SELECT id FROM outs WHERE artifact_id = ?) + +delete.artifact.by.gid = DELETE FROM artifacts WHERE gid = ?::uuid
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/messages.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,467 @@ +false=Nein +true=Ja + +state.winfo.river = River +state.winfo.calculation_mode = Calculation Mode +state.winfo.location_distance = Location or distance selection +state.winfo.wq = Input for W/Q data +state.winfo.wq_adapted = Input for W/Q data +state.winfo.location = Choose the location +state.winfo.distance = Choose the range +state.winfo.distance_only = Range selection +state.winfo.uesk.wsp = Choose the waterlevel +state.winfo.uesk.dgm = Digital Terrain Model +state.winfo.uesk.profiles = Interpolated Profiles +state.winfo.uesk.floodplain = Lateral Boundary +state.winfo.uesk.differences = Differenzen between waterlevel and terrain +state.winfo.uesk.scenario = Flood Plain / Scenario +state.winfo.waterlevel_pair_select = Chosen differences +state.winfo.historicalq.reference_gauge = Selection of Reference Gauge +state.winfo.historicalq.timerange = Selection of Evaluation time +state.winfo.historicalq.mode = Selecion of analyses +state.winfo.reference.curve.input.start = Chosen Reference +state.winfo.reference.curve.input.end = Chosen Evaluation +state.fix.river = River +state.fix.calculation.mode = Calculation Mode +state.fix.location = Distance +state.fix.period = Period +state.fix.gaugerange = Gaugerange +state.fix.eventselect = Event selection +state.fix.analysis.referenceperiod = Reference period +state.fix.analysis.analysisperiods = Analysis period +state.fix.analysis.function = Function +state.fix.analysis.preprocessing = Preprocessing +state.fix.preprocess=preprocess +state.fix.vollmer.function=Function +state.fix.vollmer.preprocessing = Aufbereiten +state.fix.vollmer.qa = Input for W/Q data + +state.minfo.river = River +state.minfo.calculation_mode = Calculation Mode +state.minfo.distance_only = Range selection +state.minfo.dischargestate = Selection of discharge state and channel +state.minfo.sq.location=Location +state.minfo.sq.period=Periods +state.minfo.sq.outliers=Outliers +state.minfo.bed.year_epoch=Year/Epoch +state.minfo.bed.difference_select=Differences +state.minfo.year=Year +state.minfo.epoch=Epoch +state.minfo.bed.location = Location/Distance +state.minfo.bed.periods = Periods +state.minfo.bed.char_diameter = Characteristic Diameter +state.minfo.soundings = Choose Soundings + +year=Year +epoch=Epoch +soundings = Soundings / Epochs + +historical.mode.w = Waterlevel Analyse +historical.mode.q = Discharge Analyse + +calc.surface.curve = Water Level/Surface Curve +calc.flood.map = Flood Plain +calc.discharge.curve = State Discharge Curve/Stage Discharge Relation +calc.duration.curve = Duration Curve +calc.discharge.longitudinal.section = TODO (W bei...) +calc.w.differences = Differences +calc.historical.discharge.curve = Historical Discharge Curve +calc.reference.curve = Reference Curve +calc.fixation.default = Fixingg +calc.fixation.vollmer = Generative Waterlevel +calc.bed.middle = Middle Bed Height +calc.bed.diff = Bed Height Difference +calc.bed.quality = Bed Quality +calc.sediment.load = Sediment Load +calc.flow.velocity = Flow Velocity +calc.sq.relation = Load Discharge Relation +calc.bed.d90 = D90 +calc.bed.d84 = D84 +calc.bed.d80 = D80 +calc.bed.d75 = D75 +calc.bed.d70 = D70 +calc.bed.d60 = D60 +calc.bed.d50 = D50 +calc.bed.d40 = D40 +calc.bed.d30 = D30 +calc.bed.d25 = D25 +calc.bed.d20 = D20 +calc.bed.d16 = D16 +calc.bed.d10 = D10 +calc.bed.dmin = Dmin +calc.bed.dmax = Dmax +calc.bed.dmid = Dmid + +calculation.analysis = Fixinganalysis +calculation.vollmer = relocated Waterlevel Calculation + +state.chart.river = River +state.chart.type = Charttype + +chart.new.durationcurve = Duration Curve +chart.new.computeddischargecurve = Discharge Curve +chart.new.longitudinal_section = Longitudinal Section +chart.new.w_differences = Differences +chart.new.crosssection = Cross Section + +cross_section = Cross Section + +reference_curve = Reference Curve +reference_curve_normalized = Normalized Reference Curve + +scenario.current = Current +scenario.potentiel = Potentiel +scenario.scenario = Scenario + +floodplain.option = Use Floodplain? +floodplain.active = Activ +floodplain.inactive = Inactiv + +river = River +calculation_mode = Calculation Mode +ld_locations = Location(s) +main_channel = Main channel +total_channel = Total channel + +chart.longitudinal.section.title = W-Longitudinal Section +chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.xaxis.label = {0}-km +chart.longitudinal.section.yaxis.label = W [{0}] +chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] +chart.longitudinal.annotations.label = {0}.km + +chart.cross_section.title = Cross Section for river {0} +chart.cross_section.subtitle = {0}-km: {1,number,#.###} +chart.cross_section.xaxis.label = Distance [m] +chart.cross_section.yaxis.label = W [NN + m] + +chart.discharge.curve.title = Discharge Curve +chart.discharge.curve.xaxis.label = Q [m\u00b3/s] +chart.discharge.curve.yaxis.label = W [cm] +chart.discharge.curve.curve.valid.from = {0} (valid from {1,date,short}) +chart.discharge.curve.curve.valid.range = {0} (valid from {1,date,short} - {2,date,short}) +chart.computed.discharge.curve.title = Discharge Curve +chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} +chart.computed.discharge.curve.yaxis.label = W [NN + m] +chart.computed.discharge.curve.curve.label = Discharge Curve {0} km {1} +chart.computed.discharge.curve.gauge = Discharge curve at gauge {0} (km {1}) +chart.duration.curve.title = Duration Curve +chart.duration.curve.subtitle = {0}-km: {1,number,#.###} +chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] +chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Waterlevel duration curve for {0} (km: {1}) +chart.duration.curve.curve.q = Discharge duration curve for {0} (km: {1}) +chart.historical.discharge.title = Historical Discharge Curves +chart.historical.discharge.subtitle = Gauge {0} +chart.historical.discharge.xaxis.label = Time +chart.historical.discharge.yaxis.label = Q [m\u00b3/s] +chart.historical.discharge.yaxis.second.label = W [cm] + +chart.reference.curve.title = Reference Curve +chart.reference.curve.subtitle = {0} + +chart.reference.curve.x.axis.in.cm = Reference Gauge(s) [cm] +chart.reference.curve.x.axis.in.m = Reference Station [NN + m] +chart.reference.curve.y.axis.in.cm = Target Gauge(s) [cm] +chart.reference.curve.y.axis.in.m = Target Station(s) [NN + m] + +chart.w_differences.title = Differences +chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.yaxis.label = m +chart.w_differences.yaxis.second.label = W [NN + m] + +chart.normalized.reference.curve.title = Reduced Reference Curve + +chart.fixings.wq.title = Fixings Analysis at km {0} +chart.fixings.wq.subtitle=River: {0}; Range: {1,date,short} to {2,date,short}; Reference period: {3,date,short} to {4,date,short} +chart.fixings.wq.subtitle1={0,date,short} to {1,date,short} +chart.fixings.analysis.title = Longitudinal section at km {0} + +chart.bedquality.title=Bed Longitudinal Section +chart.bedquality.xaxis.label=River-Km +chart.bedquality.yaxis.label=Diameter [m] +chart.bedquality.yaxis.label.porosity=Porosity [%] +chart.bedquality.yaxis.label.density=Density [t/m\u00b3] + +chart.sq_relation.xaxis.label = Discharge [m\u00b3/s] +chart.sq_relation.yaxis.label = Transport [kg/s] +chart.sq_relation_a.title = Feinkornanteil +chart.sq_relation_b.title = Sand (Suspensionstransport) +chart.sq_relation_c.title = Sand (Geschiebetransport) +chart.sq_relation_d.title = Fein- und Mittelkies +chart.sq_relation_e.title = Grobkornanteil (> Mittelkies) +chart.sq_relation_f.title = Geschiebetransport gesamt +facet.sq_relation.curve = Potenziell (Geschiebedaten) +facet.sq_relation.measurements = Geschiebedaten +facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0} +facet.sq_relation.outlier.curve = Potenziell Durchgang {0} +facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0} + +facet.longitudinal_section.annotations = POIs +facet.discharge_curves.mainvalues.q = Q (main values) +facet.discharge_curves.mainvalues.w = W (main values) +facet.flow_velocity.mainchannel = v Mainchannel at {0} +facet.flow_velocity.totalchannel = v Totalchannel at {0} +facet.flow_velocity.tauchannel = TAU Mainchannel at {0} +facet.bedheight_middle.single = Bed Height {0,number,####} +facet.bedheight_middle.epoch = Bed Height Epoch {0,number,####} - {1,number,####} +facet.bedquality.bed.porosity.toplayer = Porosity ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.porosity.sublayer = Porosity ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.toplayer = Density ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.sublayer = Density ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.diameter.toplayer = {0}_Bed ({1,date} - {2,date}) ({3}) +facet.bedquality.bed.diameter.sublayer = {0}_Bed ({1,date} - {2,date}) ({3}) +facet.bedquality.bedload.diameter = {0}_Bedload +bedquality.toplayer = 0.0m - 0.3m +bedquality.sublayer = 0.1m - 0.5m + +export.waterlevel.csv.header.km = River-Km +export.waterlevel.csv.header.w = W [NN + m] +export.waterlevel.csv.header.q = Q [m\u00b3/s] +export.waterlevel.csv.header.q.desc = Description +export.waterlevel.csv.header.location = Location +export.waterlevel.csv.header.gauge = Reference Gauge +export.waterlevel.csv.meta.result = # Calculation Output - {0} - Waterlevel - FLYS 3 +export.waterlevel.csv.meta.creation = # Time of creation: {0} +export.waterlevel.csv.meta.calculationbase = # Calculation base: {0} +export.waterlevel.csv.meta.river = # River: {0} +export.waterlevel.csv.meta.range = # Location/Range (km): {0} - {1} +export.waterlevel.csv.meta.gauge = # Gauge: {0} +export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} +export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1} +export.waterlevel.csv.not.in.gauge.range = Outside selected gauge +export.computed.discharge.curve.csv.header.w = W [NN + m] +export.computed.discharge.curve.csv.header.q = Q [m\u00b3/s] +export.duration.curve.csv.header.duration = D [Days] +export.duration.curve.csv.header.w = W [NN + m] +export.duration.curve.csv.header.q = Q [m\u00b3/s] +export.discharge.longitudinal.section.csv.header.km = River-Km +export.discharge.longitudinal.section.csv.header.w = W [NN + m] +export.discharge.longitudinal.section.csv.header.cw = W corr. +export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s] +export.discharge.curve.at.header = Computed Discharge Curve for {0} {0}-km: {1} +export.historical.discharge.csv.header.timerange = Timerange +export.historical.discharge.csv.header.waterlevel = Waterlevel +export.historical.discharge.csv.header.discharge = Discharge +export.historical.discharge.csv.header.diff = Difference +export.historical.discharge.csv.header.gaugename = Gaugename +export.reference_curve.csv.header.km = km +export.reference_curve.csv.header.w.cm = W (cm at Gauge) +export.reference_curve.csv.header.w.m = W (m + NHN) +export.reference_curve.csv.header.w.q = equiv. Q (m\u00b3/s) + +export.waterlevel.pdf.mode = Waterlevel +export.computed.discharge.pdf.mode = Computed Dischargecurve +export.duration.pdf.mode = Durationcurve +export.wdifferences.pdf.mode = W Differences +export.historical.discharge.pdf.mode = Historical Discharge +export.reference_curve.pdf.mode = Reference Curve +export.computed.discharge.pdf.file = /jasper/computed-discharge_en.jasper +export.duration.pdf.file = /jasper/duration_en.jasper +export.waterlevel.pdf.file = /jasper/waterlevel_en.jasper +export.wdifferences.pdf.file = /jasper/wdifferences_en.jasper +export.historical.discharge.pdf.file = /jasper/historical-discharge_en.jasper +export.reference_curve.pdf.file = /jasper/reference_en.jasper +export.reference_curve.pdf.file.gauge = /jasper/reference_en_gauge.jasper +export.reference_curve.pdf.file.gauge.end = /jasper/reference_en_gauge_end.jasper +export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_en_gauge_start_end.jasper +export.flow_velocity.csv.header.km = River Km +export.flow_velocity.csv.header.v_total = v Total Channel +export.flow_velocity.csv.header.v_main = v Main Channel +export.flow_velocity.csv.header.tau_main = TAU Main Channel +export.flow_velocity.csv.header.q = Q [m\u00b3/s] +export.flow_velocity.csv.header.locations = Location +export.bedheight_middle.csv.header.km = River km +export.bedheight_middle.csv.header.sounding = Sounding / Epoch +export.bedheight_middle.csv.header.height = middle Bed Height +export.bedheight_middle.csv.header.uncertainty = Uncertainty [m] +export.bedheight_middle.csv.header.datagap = Data Gap +export.bedheight_middle.csv.header.soundingwidth = Sounding Width [m] +export.bedheight_middle.csv.header.width = morphological active width [m] +export.bedheight_middle.csv.header.locations = Location +export.sqrelation.csv.header.parameter = Parameter +export.sqrelation.csv.header.station = Station +export.sqrelation.csv.header.km = River-Km +export.sqrelation.csv.header.function = Function +export.sqrelation.csv.header.gauge = Gauge +export.sqrelation.csv.header.coeff.a = a +export.sqrelation.csv.header.coeff.b = b +export.sqrelation.csv.header.coeff.q = Q +export.sqrelation.csv.header.coeff.r = r^2 +export.sqrelation.csv.header.n.total = n total +export.sqrelation.csv.header.n.outliers = n outliers +export.sqrelation.csv.header.c.duan = C (DUAN) +export.sqrelation.csv.header.c.ferguson = C (FERGUSON) +export.sqrelation.csv.header.variance = Standard variance + +floodmap.wmsbackground = Background Map +floodmap.riveraxis = River Axis +floodmap.uesk = Floodmap +floodmap.barriers = Digitized Objects +floodmap.kms = Kilometrage +floodmap.qps = Crosssection Tracks +floodmap.hws = Flood Control Works +floodmap.catchment = Catchment +floodmap.floodplain = Floodplain +floodmap.lines = Lines +floodmap.buildings = Buildings +floodmap.fixpoints = Fixpoints +floodmap.floodmaps = Floodmaps +floodmap.usershape = User data + +wsplgen.job.queued = WSPLGEN job in queue. +wsplgen.job.error = An unexpected error while starting WSPLGEN occured. + +wsp.selected.string = {0} + +Mosel = Mosel +Saar = Saar +Elbe = Elbe + +state.map.river = River + +spline.interpolation.failed = Spline interpolation failed. +cannot.find.w.for.q = Cannot find W for Q = {0,number,#.##}. +cannot.find.q = Cannot find Q = {0,number,#.##}. +no.ws.found = No Ws found. +no.q.found.in.column = No Q found in {0,integer} column. +spline.creation.failed = Spline creation failed. +cannot.find.w.or.q = Cannot find W or Q. +km.not.found = Cannot find km. +cannot.create.wq.relation = Cannot create W/Q relation. +cannot.create.index.q.relation = Cannot create index/Q relation. + +w.w.qkm1.failed = Calculating Q for WST index {0,number,#.##} failed. +w.w.wkm1.failed = Calculating W for Q = {0,number,#.##} / WST index {1,number,#.##} failed. +w.w.qkm2.failed = Calculating Q for WST index {0,number,#.##} failed. +w.w.wkm2.failed = Calculating W for Q = {0,number,#.##} / WST index {1,number,#.##} failed. + +cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date} +cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange. +cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge. + +more.than.one.q.for.w = Found more Qs for W = {0,number,#.##}. + +no.river.selected = No river selected. +no.gauge.selected = No gauge selected. +no.locations.selected = No locations selected. +no.kms.selected = No KMs selected. +converting.ws.to.qs.failed = Converting Ws to Qs failed. +no.wst.for.river = No WST found for selected river. +no.range.found = No range found. +no.gauge.found.for.km = No gauge found for KM. +cannot.create.segments = Cannot create segments. +cannot.compute.discharge.curve = Cannot create discharge curve. +cannot.find.ds = Cannot find Ds. +no.segments.found = No segments found. +no.values.given = No values given. +cannot.interpolate.w.q = Cannot interpolate W/Q. +manualpoints = Manual Points + +no.reference.start.km = No reference start station given. +no.reference.end.kms = No reference end station(s) given. +waterlevels = Waterlevels + +help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe +help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO +help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten +help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke +help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten +help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen +help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels +help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels +help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke +help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage +help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells +help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile +help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung +help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde +help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario +help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels +help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes +help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart + +fix.reference.period=Reference period +fix.reference.period.event=Reference event +fix.reference.period.event.short=R +fix.analysis.short=A +fix.analysis.periods=Analysis periods +fix.derivative=Derivative +fix.outlier=Outlier +fix.analysis=Analysis event +fix.deviation=Standard deviation +fix.reference.deviation=Reference deviation +fix.vollmer.wq.curve=W/Q +fix.vollmer.wq.outliers=Outliers +fix.vollmer.wq.events=Events +qsectors=Discharge Sectors + +chart.fix.deltawt.title=Difference from compensating curve at kilometer {0} +chart.fix.deltawt.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short}; Reference period: {3,date,short} bis {4,date,short} +chart.fix.deltawt.xaxis.label=Date +chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm] + +chart.fix.wq.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short} +chart.fixings.derivedcurve.title = Derived curve at km {0} +chart.fixings.deltawt.title = Differences from fitted curve at km {0} + +chart.fixings.longitudinalsection.title=Longitudinal section + +export.fixings.deltawt.csv.header.km=km +export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm] +export.fixings.deltawt.csv.header.q=Discharge [m\u00b3/s] +export.fixings.deltawt.csv.header.w=Waterlevel [m] +export.fixings.deltawt.csv.header.t=Date +export.fixings.deltawt.csv.t.format=yyyy/MM/dd +export.fixings.deltawt.csv.header.time.range=State +export.fixings.deltawt.csv.reference=R +export.fixings.deltawt.csv.analysis=A{0,number,integer} + +fix.missing.river=Missing river +fix.missing.from=Missing start km +fix.missing.to=Missing end km +fix.missing.step="Missing step width +fix.missing.function=Missing function type +fix.missing.events=Missing list of events +fix.missing.reference.period=Missing reference period +fix.missing.analysis.periods=Missing analysis periods +fix.missing.qstart.sector=Missing discharge start sector +fix.missing.qend.sector=Missing discharge end sector +fix.missing.prepocessing=Missing info about preprocessing +fix.no.overview.available=No overview available +fix.invalid.function.name=Name of function unknown +fix.too.less.data.colums=Too less data columns for calculation +fix.fitting.failed=Fitting failed +fix.invalid.values=Invalid values +fix.cannot.load.data=Cannot fetch data from database + +fix.km.chart.q.sector.border0=(MNQ + MQ)/2 +fix.km.chart.q.sector.border1=(MQ + MHQ)/2 +fix.km.chart.q.sector.border2=HQ5 +fix.km.chart.label.date=yyyy/MM/dd +fix.km.chart.title=Fixings {0} km {1,number,#.###} +fix.km.chart.q.axis=Q [m\u00b3/s] +fix.km.chart.w.axis=W [NN + m] +fix.km.chart.measured=measured +fix.km.chart.interpolated=interpolated + +fix.export.at.header = Exported fixings discharge curve for {0} {0}-km: {1} +sq.km.chart.label = Measuring Points +sq.km.chart.title = Measuring Points +sq.km.chart.km.axis = km +sq.km.chart.date.axis = Date + +module.winfo = WINFO +module.minfo = MINFO +module.fixanalysis = Fix Analysis +module.new_map = New Map +module.new_chart = New Chart + +load_diameter = Bedload Diameter +bed_diameter = Bed Diameter + +area.label.template = Area = %s m\u00b3 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/messages_de.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,470 @@ +false=Nein +true=Ja + +state.winfo.river = Gew\u00e4sser +state.winfo.calculation_mode = Berechnungsart +state.winfo.location_distance = Wahl des Berechnungsortes/strecke +state.winfo.wq = Eingabe f\u00fcr W/Q Daten +state.winfo.wq_adapted = Eingabe f\u00fcr W/Q Daten +state.winfo.location = Wahl des Berechnungsortes +state.winfo.distance = Wahl der Berechnungsstrecke +state.winfo.distance_only = Wahl der Berechnungsstrecke +state.winfo.uesk.wsp = Wahl der Wasserspiegellage +state.winfo.uesk.dgm = Digitales Gel\u00e4ndemodell +state.winfo.uesk.profiles = Interpolierte Profile +state.winfo.uesk.floodplain = Laterale Begrenzung +state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde +state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario +state.winfo.waterlevel_pair_select = Ausgew\u00e4hlte Differenzen +state.winfo.historicalq.reference_gauge = Wahl des Bezugspegels +state.winfo.historicalq.timerange = Wahl des Auswertezeitraums +state.winfo.historicalq.mode = Wahl der Analyseart +state.winfo.reference.curve.input.start = Bezugsort +state.winfo.reference.curve.input.end = Zielort(e) +state.fix.river = Gew\u00e4sser +state.fix.calculation.mode = Berechnungsart +state.fix.location = Strecke +state.fix.period = Zeitraum +state.fix.gaugerange = Abflussklassen +state.fix.eventselect = Ereignisauswahl +state.fix.analysis.referenceperiod = Bezugszeitraum +state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume +state.fix.analysis.function = Funktion +state.fix.analysis.preprocessing = Aufbereiten +state.fix.preprocess=aufbereiten +state.fix.vollmer.function=Funktion +state.fix.vollmer.preprocessing = Aufbereiten +state.fix.vollmer.qa = Eingabe f\u00e4r W/Q Daten + +state.minfo.river = Gew\u00e4sser +state.minfo.calculation_mode = Berechnungsart +state.minfo.distance_only = Wahl der Berechnungsstrecke +state.minfo.dischargestate = Abflusszustand und Gerinne +state.minfo.sq.location=Ort +state.minfo.sq.period=Zeitraum +state.minfo.sq.outliers=Ausrei\u00dfer +state.minfo.bed.year_epoch=Jahr/Epoche +state.minfo.bed.difference_select=Differenzen +state.minfo.year=Jahr +state.minfo.epoch=Epoche +state.minfo.bed.location = Ort(e)/Strecke +state.minfo.bed.periods = Zeitraum/Zeitr\u00e4ume +state.minfo.bed.char_diameter = Charakteristischer Durchmesser +state.minfo.soundings = Wahl der Peilungen + +year=Jahr +epoch=Epoche +soundings = Peilungen / Epochen + +historical.mode.w = Wasserstandsanalyse +historical.mode.q = Abflussanalyse + +calc.surface.curve = Wasserstand/Wasserspiegellage +calc.flood.map = \u00dcberschwemmungsfl\u00e4che +calc.discharge.curve = Abflusskurve/Abflusstafel +calc.duration.curve = Dauerlinie +calc.discharge.longitudinal.section = W f\u00fcr ungleichwertigen Abflussl\u00e4ngsschnitt +calc.w.differences = Differenzen +calc.historical.discharge.curve = Hist. Abflusskurven +calc.reference.curve = Bezugslinie +calc.fixation.default = Fixierungsanalyse +calc.fixation.vollmer = Ausgelagerte Wasserspiegellage +calc.bed.middle = Mittlere Sohlh\u00f6he +calc.bed.diff = Sohlh\u00f6hendifferenz +calc.bed.quality = Sohlbeschaffenheit +calc.sediment.load = Sedimentfracht +calc.flow.velocity = Flie\u00dfgeschwindigkeit +calc.sq.relation = Transport-Abfluss Beziehung +calc.bed.d90 = D90 +calc.bed.d84 = D84 +calc.bed.d80 = D80 +calc.bed.d75 = D75 +calc.bed.d70 = D70 +calc.bed.d60 = D60 +calc.bed.d50 = D50 +calc.bed.d40 = D40 +calc.bed.d30 = D30 +calc.bed.d25 = D25 +calc.bed.d20 = D20 +calc.bed.d16 = D16 +calc.bed.d10 = D10 +calc.bed.dmin = Dmin +calc.bed.dmax = Dmax +calc.bed.dmid = Dmid + +calculation.analysis = Fixierungsanalyse +calculation.vollmer = ausgelagerte Wasserspiegellage + +state.chart.river = Gew\u00e4sser +state.chart.type = Diagrammtyp + +chart.new.durationcurve = Dauerlinie +chart.new.computeddischargecurve = Abflusskurve +chart.new.longitudinal_section = L\u00e4ngsschnitt +chart.new.w_differences = Differenzen +chart.new.crosssection = Querprofil + +cross_section = Querprofil + +reference_curve = Bezugslinie +reference_curve_normalized = Reduzierte Bezugslinie + +scenario.current = Aktuell +scenario.potentiel = Potenziell +scenario.scenario = Szenario + +floodplain.option = Talaue verwenden? +floodplain.active = Aktiv +floodplain.inactive = Inaktiv + +river = Fluss +calculation_mode = Berechnungsart +ld_locations = Ort(e) +main_channel = Hauptgerinne +total_channel = Gesamtgerinne + +chart.cross_section.title = Querprofildiagramm f\u00fcr Gew\u00e4sser {0} +chart.cross_section.subtitle = {0}-km: {1,number,#.###} +chart.cross_section.xaxis.label = Abstand [m] +chart.cross_section.yaxis.label = W [NN + m] + +chart.longitudinal.section.title = W-L\u00e4ngsschnitt +chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###} +chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.xaxis.label = {0}-km +chart.longitudinal.section.yaxis.label = W [{0}] +chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] +chart.longitudinal.annotations.label = {0}.km +chart.discharge.curve.title = Abflusskurve +chart.discharge.curve.xaxis.label = Q [m\u00b3/s] +chart.discharge.curve.yaxis.label = W [cm] +chart.discharge.curve.curve.valid.from = {0} (g\u00fcltig ab {1,date,medium}) +chart.discharge.curve.curve.valid.range = {0} (g\u00fcltig ab {1,date,medium} - {2,date,medium}) +chart.computed.discharge.curve.title = Abflusskurve +chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} +chart.computed.discharge.curve.yaxis.label = W [NN + m] +chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1} +chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1}) +chart.duration.curve.title = Dauerlinie +chart.duration.curve.subtitle = {0}-km: {1,number,#.###} +chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] +chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} (km:{1}) +chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} (km:{1}) +chart.historical.discharge.title = Historische Abflusskurven +chart.historical.discharge.subtitle = Pegel {0} +chart.historical.discharge.xaxis.label = Zeit +chart.historical.discharge.yaxis.label = Q [m\u00b3/s] +chart.historical.discharge.yaxis.second.label = W [cm] + +chart.reference.curve.title = Bezugslinie +chart.reference.curve.subtitle = {0} + +chart.fixings.derivedcurve.title = Ableitungskurve an Kilometer {0} +chart.fixings.deltawt.title = Abweichungen von der Ausgleichskurve an Kilometer {0} +chart.fixings.analysis.title = L\u00e4ngsschnitt an Kilometer {0} +chart.fixings.wq.title = Fixierungsanalyse an Kilometer {0} + + +chart.reference.curve.x.axis.in.cm = Bezugspegel [cm] +chart.reference.curve.x.axis.in.m = Bezugsort [NN + m] +chart.reference.curve.y.axis.in.cm = Zielpegel [cm] +chart.reference.curve.y.axis.in.m = Zielort(e) [NN + m] + +chart.normalized.reference.curve.title = Reduzierte Bezugslinie + +chart.w_differences.title = Differenzen +chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.yaxis.label = m +chart.w_differences.yaxis.second.label = W [NN + m] + +chart.bedquality.title=Sohlen L\u00e4ngsschnitt +chart.bedquality.xaxis.label=Fluss-Km +chart.bedquality.yaxis.label=Durchmesser [m] +chart.bedquality.yaxis.label.porosity=Porosit\u00e4t [%] +chart.bedquality.yaxis.label.density=Dichte [t/m\u00b3] + +chart.sq_relation.xaxis.label = Abfluss [m\u00b3/s] +chart.sq_relation.yaxis.label = Transport [kg/s] +chart.sq_relation_a.title = Feinkornanteil +chart.sq_relation_b.title = Sand (Suspensionstransport) +chart.sq_relation_c.title = Sand (Geschiebetransport) +chart.sq_relation_d.title = Fein- und Mittelkies +chart.sq_relation_e.title = Grobkornanteil (> Mittelkies) +chart.sq_relation_f.title = Geschiebetransport gesamt +facet.sq_relation.curve = Potenziell (Geschiebedaten) +facet.sq_relation.measurements = Geschiebedaten +facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0} +facet.sq_relation.outlier.curve = Potenziell Durchgang {0} +facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0} + +facet.longitudinal_section.annotations = Streckenfavoriten +facet.discharge_curves.mainvalues.q = Q (Haupt- und Extremwerte) +facet.discharge_curves.mainvalues.w = W (Haupt- und Extremwerte) +facet.flow_velocity.mainchannel = v Hauptgerinne bei {0} +facet.flow_velocity.totalchannel = v Gesamtgerinne bei {0} +facet.flow_velocity.tauchannel = TAU Hauptgerinne bei {0} +facet.bedheight_middle.single = Sohlh\u00f6he {0,number,####} +facet.bedheight_middle.epoch = Sohlh\u00f6he Epoche {0,number,####} - {1,number,####} +facet.bedquality.bed.porosity.toplayer = Porosit\u00e4t ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.porosity.sublayer = Porosit\u00e4t ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.toplayer = Dichte ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.sublayer = Dichte ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.diameter.toplayer = {0}_Sohle ({1,date} - {2,date}) ({3}) +facet.bedquality.bed.diameter.sublayer = {0}_Sohle ({1,date} - {2,date}) ({3}) +facet.bedquality.bedload.diameter = {0}_Geschiebe +bedquality.toplayer = 0,0m - 0,3m +bedquality.sublayer = 0,1m - 0,5m + +export.waterlevel.csv.header.km = Fluss-Km +export.waterlevel.csv.header.w = W [NN + m] +export.waterlevel.csv.header.q = Q [m\u00b3/s] +export.waterlevel.csv.header.q.desc = Bezeichnung +export.waterlevel.csv.header.location = Lage +export.waterlevel.csv.header.gauge = Bezugspegel +export.waterlevel.csv.meta.result = # Ergebnisausgabe - {0} - Wasserstand - FLYS 3 +export.waterlevel.csv.meta.creation = # Datum der Erstellung: {0} +export.waterlevel.csv.meta.calculationbase = # Berechnungsgrundlage: {0} +export.waterlevel.csv.meta.river = # Gew\u00e4sser: {0} +export.waterlevel.csv.meta.range = # Ort/Bereich (km): {0} - {1} +export.waterlevel.csv.meta.gauge = # Bezugspegel: {0} +export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} +export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1} +export.waterlevel.csv.not.in.gauge.range = au\u00dferhalb gew\u00e4hlter Bezugspegels +export.computed.discharge.curve.csv.header.w = W [NN + m] +export.computed.discharge.curve.csv.header.q = Q [m\u00b3/s] +export.duration.curve.csv.header.duration = D [Tagen] +export.duration.curve.csv.header.w = W [NN + m] +export.duration.curve.csv.header.q = Q [m\u00b3/s] +export.discharge.longitudinal.section.csv.header.km = Fluss-Km +export.discharge.longitudinal.section.csv.header.w = W [NN + m] +export.discharge.longitudinal.section.csv.header.cw = W korr. +export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s] +export.discharge.curve.at.header = Berechnete Abflusskurve f\u00fcr {0} {0}-km: {1} +export.historical.discharge.csv.header.timerange = Zeitraum +export.historical.discharge.csv.header.waterlevel = Wasserstand +export.historical.discharge.csv.header.discharge = Abfluss +export.historical.discharge.csv.header.diff = Abflussdifferenz zur Bezugskurve +export.historical.discharge.csv.header.gaugename = Pegelname +export.reference_curve.csv.header.km = km +export.reference_curve.csv.header.w.cm = W (cm am Pegel) +export.reference_curve.csv.header.w.m = W (m + NHN) +export.reference_curve.csv.header.w.q = gleichw. Q (m\u00b3/s) + + +export.waterlevel.pdf.mode = Wasserstand +export.computed.discharge.pdf.mode = Abflusskurve +export.duration.pdf.mode = Dauerlinie +export.wdifferences.pdf.mode = W Differenzen +export.historical.discharge.pdf.mode = Historischer Abfluss +export.reference_curve.pdf.mode = Bezugslinie +export.computed.discharge.pdf.file = /jasper/computed-discharge.jasper +export.duration.pdf.file = /jasper/duration.jasper +export.waterlevel.pdf.file = /jasper/waterlevel.jasper +export.wdifferences.pdf.file = /jasper/wdifferences.jasper +export.historical.discharge.pdf.file = /jasper/historical-discharge.jasper +export.reference_curve.pdf.file = /jasper/reference.jasper +export.reference_curve.pdf.file.gauge = /jasper/reference_gauge.jasper +export.reference_curve.pdf.file.gauge.end = /jasper/reference_gauge_end.jasper +export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_gauge_start_end.jasper +export.flow_velocity.csv.header.km = Fluss-Km +export.flow_velocity.csv.header.v_total = v Gesamtgerinne +export.flow_velocity.csv.header.v_main = v Hauptgerinne +export.flow_velocity.csv.header.tau_main = TAU Hauptgerinne +export.flow_velocity.csv.header.q = Q [m\u00b3/s] +export.flow_velocity.csv.header.locations = Streckendaten +export.bedheight_middle.csv.header.km = Fluss-km +export.bedheight_middle.csv.header.sounding = Peilung / Epoche +export.bedheight_middle.csv.header.height = gemittelte Sohl\u00f6he +export.bedheight_middle.csv.header.uncertainty = Unsicherheit [m] +export.bedheight_middle.csv.header.datagap = Datenl\u00fccke +export.bedheight_middle.csv.header.soundingwidth = Peilbreite [m] +export.bedheight_middle.csv.header.width = morphologisch aktive Breite [m] +export.bedheight_middle.csv.header.locations = Streckendaten +export.sqrelation.csv.header.parameter = Parameter +export.sqrelation.csv.header.station = Station +export.sqrelation.csv.header.km = Fluss-Km +export.sqrelation.csv.header.function = Funktion +export.sqrelation.csv.header.gauge = Pegel +export.sqrelation.csv.header.coeff.a = a +export.sqrelation.csv.header.coeff.b = b +export.sqrelation.csv.header.coeff.q = Q +export.sqrelation.csv.header.coeff.r = r^2 +export.sqrelation.csv.header.n.total = n gesamt +export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer +export.sqrelation.csv.header.c.duan = C (DUAN) +export.sqrelation.csv.header.c.ferguson = C (FERGUSON) +export.sqrelation.csv.header.variance = Standardabweichung + +floodmap.wmsbackground = Hintergrundkarte +floodmap.riveraxis = Flussachse +floodmap.uesk = \u00dcberschwemmungsfl\u00e4che +floodmap.barriers = Digitalisierte Objekte +floodmap.kms = Kilometrierung +floodmap.qps = Querprofilspuren +floodmap.hws = Hochwasserschutzanlagen +floodmap.catchment = Einzugsgebiet +floodmap.floodplain = Talaue +floodmap.lines = Linien +floodmap.buildings = Bauwerke +floodmap.fixpoints = Festpunkte +floodmap.floodmaps = \u00dcberschwemmungsfl\u00e4che +floodmap.usershape = Benutzerdaten + +wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange. +wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten. + +wsp.selected.string = {0} + +Mosel = Mosel +Saar = Saar +Elbe = Elbe + +state.map.river = Gew\u00e4sser + +spline.interpolation.failed = Spline interpolation fehlgeschlagen. +cannot.find.w.for.q = W zu Q = {0,number,#.##} kann nicht ermittelt werden. +cannot.find.q = Q = {0,number,#.##} konnte nicht gefunden werden. +no.ws.found = Keine Ws gefunden. +no.q.found.in.column = In Spalte {0,integer} wurde kein Q gefunden. +spline.creation.failed = Spline creation failed. +cannot.find.w.or.q = W oder Q konnten nicht ermittelt werden. +km.not.found = Passender Kilometer konnte nicht gefunden werden. +cannot.create.wq.relation = W/Q-Beziehung konnte nicht ermittelt werden. +cannot.create.index.q.relation = Spaltenindex/Q-Beziehung konnte nicht erstellt werden. + +w.w.qkm1.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. +w.w.wkm1.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. +w.w.qkm2.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. +w.w.wkm2.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. + +cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln. +cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden. +cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln. + +more.than.one.q.for.w = Mehr als ein Q f\u00fcr W = {0,number,#.##} gefunden. + +no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt. +no.gauge.selected = Kein Pegel ausgew\u00e4hlt. +no.locations.selected = Keine Orte angegeben. +no.kms.selected = Keine Kilometerstationen angegeben. +converting.ws.to.qs.failed = Konvertierung von Ws zu Qs fehlgeschlagen. +no.wst.for.river = Keine zum Gew\u00e4sser passende WST gefunden. +no.range.found = Kein passender Pegel gefunden. +no.gauge.found.for.km = Zur gegebenen Kilometerstation existiert kein Pegel. +cannot.create.segments = Flussabschnitte konnten nicht erzeugt werden. +cannot.compute.discharge.curve = Die Abflusskurve konnte nicht berechnet werden.. +cannot.find.ds = Dauerzahlen konnten nicht gefunden werden. +no.segments.found = Keine Flussabschnitte gefunden. +no.values.given = Keine Werte angegeben. +cannot.interpolate.w.q = W/Q-Wert konnte nicht interpoliert werden. + +manualpoints = Manuelle Punkte + +no.reference.start.km = Keine Startkilometerstation angegeben. +no.reference.end.kms = Keine Endkilometerstation(en) angegeben. +waterlevels = Wasserst\u00e4nde + +help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe +help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO +help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten +help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke +help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten +help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen +help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels +help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels +help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke +help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage +help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells +help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile +help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung +help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde +help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario +help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels +help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes +help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart + +fix.reference.period=Bezugszeitraum +fix.reference.period.event=Bezugsereignis +fix.reference.period.event.short=B +fix.analysis.short=A +fix.analysis.periods=Analysezeitr\u00e4ume +fix.derivative=Ableitung +fix.outlier=Ausrei\u00dfer +fix.analysis=Analyseereignis +fix.deviation=Standardabweichung +fix.reference.deviation=Abweichung im Bezugszeitraum +fix.vollmer.wq.curve=W/Q +fix.vollmer.wq.outliers=Ausrei\u00dfer +fix.vollmer.wq.events=Ereignisse +qsectors=Abfluss-Sektoren + +chart.fix.deltawt.title=Abweichungen von der Ausgleichskurve an Kilometer {0} +chart.fix.deltawt.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short} +chart.fix.deltawt.xaxis.label=Datum +chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm] + +chart.fixings.wq.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short} +chart.fixings.wq.subtitle1={0,date,short} bis {1,date,short} + +chart.fixings.longitudinalsection.title=L\u00e4ngsschnitt + +export.fixings.deltawt.csv.header.km=km +export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm] +export.fixings.deltawt.csv.header.q=Abfluss [m\u00b3/s] +export.fixings.deltawt.csv.header.w=Wasserstand [m] +export.fixings.deltawt.csv.header.t=Datum +export.fixings.deltawt.csv.t.format=dd.MM.yyyy +export.fixings.deltawt.csv.header.time.range=Status +export.fixings.deltawt.csv.reference=B +export.fixings.deltawt.csv.analysis=A{0,number,integer} + +chart.fix.wq.subtitle=Gew\u00e4sser: {0}; Zeitraum: {1,date,short} bis {2,date,short} + +fix.missing.river=Kein Gew\u00e4sser gew\u00e4hlt +fix.missing.from=Kein Startkilometer gew\u00e4hlt +fix.missing.to=Kein Endkilometer gew\u00e4hlt +fix.missing.step=Keine Schrittweite angegeben +fix.missing.function=Unbekannter Funktions-Typ +fix.missing.events=Liste der Ereignisse fehlt +fix.missing.reference.period=Kein Bezugszeitraum angegeben +fix.missing.analysis.periods=Keine Analysezeitr\u00e4ume angegeben +fix.missing.qstart.sector=Fehlender unterer Abflusssektor +fix.missing.qend.sector=Fehlender oberer Abflusssektor +fix.missing.prepocessing=Kein Information \u00fcber Aussrei\u00dfertests vorhanden +fix.no.overview.available=Keine Daten\u00fcbersicht vorhanden +fix.invalid.function.name=Unbekannter Funktionsname +fix.too.less.data.colums=Zuwenig Daten f\u00fcr eine Kurvenanpassung +fix.fitting.failed=Kurvenanpassung fehlgeschlagen +fix.invalid.values=Ung\u00fcltige Werte +fix.cannot.load.data=Daten konnten nicht aus der Datenbank geladen werden + +fix.km.chart.q.sector.border0=(MNQ + MQ)/2 +fix.km.chart.q.sector.border1=(MQ + MHQ)/2 +fix.km.chart.q.sector.border2=HQ5 +fix.km.chart.label.date=dd.MM.yyyy +fix.km.chart.title=Fixierungen {0} km {1,number,#.###} +fix.km.chart.q.axis=Q [m\u00b3/s] +fix.km.chart.w.axis=W [NN + m] +fix.km.chart.measured=gemessen +fix.km.chart.interpolated=interpoliert + +fix.export.at.header = Abflusskurve aus der Fixierungsanalyse f\u00fcr {0} {0}-km: {1} +sq.km.chart.label = Messstellen +sq.km.chart.title = Messstellen +sq.km.chart.km.axis = km +sq.km.chart.date.axis = Datum + +module.winfo = WINFO +module.minfo = MINFO +module.fixanalysis = Fixierungsanalyse +module.new_map = Neue Karte +module.new_chart = Neues Diagramm + +load_diameter = Geschiebedurchmesser +bed_diameter = Sohldurchmesser + +area.label.template = Fl\u00e4che = %s m\u00b3 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/messages_de_DE.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,469 @@ +false=Nein +true=Ja + +state.winfo.river = Gew\u00e4sser +state.winfo.calculation_mode = Berechnungsart +state.winfo.location_distance = Wahl des Berechnungsortes/strecke +state.winfo.wq = Eingabe f\u00fcr W/Q Daten +state.winfo.wq_adapted = Eingabe f\u00fcr W/Q Daten +state.winfo.location = Wahl des Berechnungsortes +state.winfo.distance = Wahl der Berechnungsstrecke +state.winfo.distance_only = Wahl der Berechnungsstrecke +state.winfo.uesk.wsp = Wahl der Wasserspiegellage +state.winfo.uesk.dgm = Digitales Gel\u00e4ndemodell +state.winfo.uesk.profiles = Interpolierte Profile +state.winfo.uesk.floodplain = Laterale Begrenzung +state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde +state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario +state.winfo.waterlevel_pair_select = Ausgew\u00e4hlte Differenzen +state.winfo.historicalq.reference_gauge = Wahl des Bezugspegels +state.winfo.historicalq.timerange = Wahl des Auswertezeitraums +state.winfo.historicalq.mode = Wahl der Analyseart +state.winfo.reference.curve.input.start = Bezugsort +state.winfo.reference.curve.input.end = Zielort(e) +state.fix.river = Gew\u00e4sser +state.fix.calculation.mode = Berechnungsart +state.fix.location = Strecke +state.fix.period = Zeitraum +state.fix.gaugerange = Abflussklassen +state.fix.eventselect = Ereignisauswahl +state.fix.analysis.referenceperiod = Bezugszeitraum +state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume +state.fix.analysis.function = Funktion +state.fix.analysis.preprocessing = Aufbereitung +state.fix.preprocess=aufbereiten +state.fix.vollmer.function=Funktion +state.fix.vollmer.preprocessing = Aufbereiten +state.fix.vollmer.qa = Eingabe f\u00e4r W/Q Daten + +state.minfo.river = Gew\u00e4sser +state.minfo.calculation_mode = Berechnungsart +state.minfo.distance_only = Wahl der Berechnungsstrecke +state.minfo.dischargestate = Abflusszustand und Gerinne +state.minfo.sq.location=Ort +state.minfo.sq.period=Zeitraum +state.minfo.sq.outliers=Ausrei\u00dfer +state.minfo.bed.year_epoch=Jahr/Epoche +state.minfo.bed.difference_select=Differenzen +state.minfo.year=Jahr +state.minfo.epoch=Epoche +state.minfo.bed.location = Ort(e)/Strecke +state.minfo.bed.periods = Zeitraum/Zeitr\u00e4ume +state.minfo.bed.char_diameter = Charakteristischer Durchmesser +state.minfo.soundings = Wahl der Peilungen + +year=Jahr +epoch=Epoche +soundings = Peilungen / Epochen + +historical.mode.w = Wasserstandsanalyse +historical.mode.q = Abflussanalyse + +calc.surface.curve = Wasserstand/Wasserspiegellage +calc.flood.map = \u00dcberschwemmungsfl\u00e4che +calc.discharge.curve = Abflusskurve/Abflusstafel +calc.duration.curve = Dauerlinie +calc.discharge.longitudinal.section = W f\u00fcr ungleichwertigen Abflussl\u00e4ngsschnitt +calc.w.differences = Differenzen +calc.historical.discharge.curve = Hist. Abflusskurven +calc.reference.curve = Bezugslinie +calc.fixation.default = Fixierung +calc.fixation.vollmer = Ausgelagerte Wasserspiegellage +calc.bed.middle = Mittlere Sohlh\u00f6he +calc.bed.diff = Sohlh\u00f6hendifferenz +calc.bed.quality = Sohlbeschaffenheit +calc.sediment.load = Sedimentfracht +calc.flow.velocity = Flie\u00dfgeschwindigkeit +calc.sq.relation = Transport-Abfluss Beziehung +calc.bed.d90 = D90 +calc.bed.d84 = D84 +calc.bed.d80 = D80 +calc.bed.d75 = D75 +calc.bed.d70 = D70 +calc.bed.d60 = D60 +calc.bed.d50 = D50 +calc.bed.d40 = D40 +calc.bed.d30 = D30 +calc.bed.d25 = D25 +calc.bed.d20 = D20 +calc.bed.d16 = D16 +calc.bed.d10 = D10 +calc.bed.dmin = Dmin +calc.bed.dmax = Dmax +calc.bed.dmid = Dmid + +calculation.analysis = Fixierungsanalyse +calculation.vollmer = ausgelagerte Wasserspiegellage + +state.chart.river = Gew\u00e4sser +state.chart.type = Diagrammtyp + +chart.new.durationcurve = Dauerlinie +chart.new.computeddischargecurve = Abflusskurve +chart.new.longitudinal_section = L\u00e4ngsschnitt +chart.new.w_differences = Differenzen +chart.new.crosssection = Querprofil + +cross_section = Querprofil + +reference_curve = Bezugslinie +reference_curve_normalized = Reduzierte Bezugslinie + +scenario.current = Aktuell +scenario.potentiel = Potenziell +scenario.scenario = Szenario + +floodplain.option = Talaue verwenden? +floodplain.active = Aktiv +floodplain.inactive = Inaktiv + +river = Fluss +calculation_mode = Berechnungsart +ld_locations = Ort(e) +main_channel = Hauptgerinne +total_channel = Gesamtgerinne + +chart.cross_section.title = Querprofildiagramm f\u00fcr Gew\u00e4sser {0} +chart.cross_section.subtitle = {0}-km: {1,number,#.###} +chart.cross_section.xaxis.label = Abstand [m] +chart.cross_section.yaxis.label = W [NN + m] + +chart.longitudinal.section.title = W-L\u00e4ngsschnitt +chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###} +chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.xaxis.label = {0}-km +chart.longitudinal.section.yaxis.label = W [{0}] +chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] +chart.longitudinal.annotations.label = {0}.km +chart.discharge.curve.title = Abflusskurve +chart.discharge.curve.xaxis.label = Q [m\u00b3/s] +chart.discharge.curve.yaxis.label = W [cm] +chart.discharge.curve.curve.valid.from = {0} (g\u00fcltig ab {1,date,medium}) +chart.discharge.curve.curve.valid.range = {0} (g\u00fcltig ab {1,date,medium} - {2,date,medium}) +chart.computed.discharge.curve.title = Abflusskurve +chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} +chart.computed.discharge.curve.yaxis.label = W [NN + m] +chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1} +chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1}) +chart.duration.curve.title = Dauerlinie +chart.duration.curve.subtitle = {0}-km: {1,number,#.###} +chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] +chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} (km:{1}) +chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} (km:{1}) +chart.historical.discharge.title = Historische Abflusskurven +chart.historical.discharge.subtitle = Pegel {0} +chart.historical.discharge.xaxis.label = Zeit +chart.historical.discharge.yaxis.label = Q [m\u00b3/s] +chart.historical.discharge.yaxis.second.label = W [cm] + +chart.reference.curve.title = Bezugslinie +chart.reference.curve.subtitle = {0} + +chart.reference.curve.x.axis.in.cm = Bezugspegel [cm] +chart.reference.curve.x.axis.in.m = Bezugsort [NN + m] +chart.reference.curve.y.axis.in.cm = Zielpegel [cm] +chart.reference.curve.y.axis.in.m = Zielort(e) [NN + m] + +chart.fixings.derivedcurve.title = Ableitungskurve an Kilometer {0} +chart.fixings.analysis.title = L\u00e4ngsschnitt an Kilometer {0} +chart.fixings.wq.title = Fixierungsanalyse an Kilometer {0} + +chart.normalized.reference.curve.title = Reduzierte Bezugslinie + +chart.w_differences.title = Differenzen +chart.w_differences.subtitle = Strecke: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.yaxis.label = m +chart.w_differences.yaxis.second.label = W [NN + m] + +chart.bedquality.title=Sohlen L\u00e4ngsschnitt +chart.bedquality.xaxis.label=Fluss-Km +chart.bedquality.yaxis.label=Durchmesser [m] +chart.bedquality.yaxis.label.porosity=Porosit\u00e4t [%] +chart.bedquality.yaxis.label.density=Dichte [t/m\u00b3] + +chart.sq_relation.xaxis.label = Abfluss [m\u00b3/s] +chart.sq_relation.yaxis.label = Transport [kg/s] +chart.sq_relation_a.title = Feinkornanteil +chart.sq_relation_b.title = Sand (Suspensionstransport) +chart.sq_relation_c.title = Sand (Geschiebetransport) +chart.sq_relation_d.title = Fein- und Mittelkies +chart.sq_relation_e.title = Grobkornanteil (> Mittelkies) +chart.sq_relation_f.title = Geschiebetransport gesamt +facet.sq_relation.curve = Potenziell (Geschiebedaten) +facet.sq_relation.measurements = Geschiebedaten +facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0} +facet.sq_relation.outlier.curve = Potenziell Durchgang {0} +facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0} + +facet.longitudinal_section.annotations = Streckenfavoriten +facet.discharge_curves.mainvalues.q = Q (Haupt- und Extremwerte) +facet.discharge_curves.mainvalues.w = W (Haupt- und Extremwerte) +facet.flow_velocity.mainchannel = v Hauptgerinne bei {0} +facet.flow_velocity.totalchannel = v Gesamtgerinne bei {0} +facet.flow_velocity.tauchannel = TAU Hauptgerinne bei {0} +facet.bedheight_middle.single = Sohlh\u00f6he {0,number,####} +facet.bedheight_middle.epoch = Sohlh\u00f6he Epoche {0,number,####} - {1,number,####} +facet.bedquality.bed.porosity.toplayer = Porosit\u00e4t ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.porosity.sublayer = Porosit\u00e4t ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.toplayer = Dichte ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.sublayer = Dichte ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.diameter.toplayer = {0}_Sohle ({1,date} - {2,date}) ({3}) +facet.bedquality.bed.diameter.sublayer = {0}_Sohle ({1,date} - {2,date}) ({3}) +facet.bedquality.bedload.diameter = {0}_Geschiebe +bedquality.toplayer = 0,0m - 0,3m +bedquality.sublayer = 0,1m - 0,5m + +export.waterlevel.csv.header.km = Fluss-Km +export.waterlevel.csv.header.w = W [NN + m] +export.waterlevel.csv.header.q = Q [m\u00b3/s] +export.waterlevel.csv.header.q.desc = Bezeichnung +export.waterlevel.csv.header.location = Lage +export.waterlevel.csv.header.gauge = Bezugspegel +export.waterlevel.csv.meta.result = # Ergebnisausgabe - {0} - Wasserstand - FLYS 3 +export.waterlevel.csv.meta.creation = # Datum der Erstellung: {0} +export.waterlevel.csv.meta.calculationbase = # Berechnungsgrundlage: {0} +export.waterlevel.csv.meta.river = # Gew\u00e4sser: {0} +export.waterlevel.csv.meta.range = # Ort/Bereich (km): {0} - {1} +export.waterlevel.csv.meta.gauge = # Bezugspegel: {0} +export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} +export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1} +export.waterlevel.csv.not.in.gauge.range = au\u00dferhalb gew\u00e4hlter Bezugspegels +export.computed.discharge.curve.csv.header.w = W [NN + m] +export.computed.discharge.curve.csv.header.q = Q [m\u00b3/s] +export.duration.curve.csv.header.duration = D [Tagen] +export.duration.curve.csv.header.w = W [NN + m] +export.duration.curve.csv.header.q = Q [m\u00b3/s] +export.discharge.longitudinal.section.csv.header.km = Fluss-Km +export.discharge.longitudinal.section.csv.header.w = W [NN + m] +export.discharge.longitudinal.section.csv.header.cw = W korr. +export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s] +export.discharge.curve.at.header = Berechnete Abflusskurve f\u00fcr {0} {0}-km: {1} +export.historical.discharge.csv.header.timerange = Zeitraum +export.historical.discharge.csv.header.waterlevel = Wasserstand +export.historical.discharge.csv.header.discharge = Abfluss +export.historical.discharge.csv.header.diff = Abflussdifferenz zur Bezugskurve +export.historical.discharge.csv.header.gaugename = Pegelname +export.reference_curve.csv.header.km = km +export.reference_curve.csv.header.w.cm = W (cm am Pegel) +export.reference_curve.csv.header.w.m = W (m + NHN) +export.reference_curve.csv.header.w.q = gleichw. Q (m\u00b3/s) + +export.waterlevel.pdf.mode = Wasserstand +export.computed.discharge.pdf.mode = Abflusskurve +export.duration.pdf.mode = Dauerline +export.wdifferences.pdf.mode = W Differenzen +export.historical.discharge.pdf.mode = Historischer Abfluss +export.reference_curve.pdf.mode = Bezugslinie +export.computed.discharge.pdf.file = /jasper/computed-discharge.jasper +export.duration.pdf.file = /jasper/duration.jasper +export.waterlevel.pdf.file = /jasper/waterlevel.jasper +export.wdifferences.pdf.file = /jasper/wdifferences.jasper +export.historical.discharge.pdf.file = /jasper/historical-discharge.jasper +export.reference_curve.pdf.file = /jasper/reference.jasper +export.reference_curve.pdf.file.gauge = /jasper/reference_gauge.jasper +export.reference_curve.pdf.file.gauge.end = /jasper/reference_gauge_end.jasper +export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_gauge_start_end.jasper +export.flow_velocity.csv.header.km = Fluss-Km +export.flow_velocity.csv.header.v_total = v Gesamtgerinne +export.flow_velocity.csv.header.v_main = v Hauptgerinne +export.flow_velocity.csv.header.tau_main = TAU Hauptgerinne +export.flow_velocity.csv.header.q = Q [m\u00b3/s] +export.flow_velocity.csv.header.locations = Streckendaten +export.bedheight_middle.csv.header.km = Fluss-km +export.bedheight_middle.csv.header.sounding = Peilung / Epoche +export.bedheight_middle.csv.header.height = gemittelte Sohl\u00f6he +export.bedheight_middle.csv.header.uncertainty = Unsicherheit [m] +export.bedheight_middle.csv.header.datagap = Datenl\u00fccke +export.bedheight_middle.csv.header.soundingwidth = Peilbreite [m] +export.bedheight_middle.csv.header.width = morphologisch aktive Breite [m] +export.bedheight_middle.csv.header.locations = Streckendaten +export.sqrelation.csv.header.parameter = Parameter +export.sqrelation.csv.header.station = Station +export.sqrelation.csv.header.km = Fluss-Km +export.sqrelation.csv.header.function = Funktion +export.sqrelation.csv.header.gauge = Pegel +export.sqrelation.csv.header.coeff.a = a +export.sqrelation.csv.header.coeff.b = b +export.sqrelation.csv.header.coeff.q = Q +export.sqrelation.csv.header.coeff.r = r^2 +export.sqrelation.csv.header.n.total = n gesamt +export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer +export.sqrelation.csv.header.c.duan = C (DUAN) +export.sqrelation.csv.header.c.ferguson = C (FERGUSON) +export.sqrelation.csv.header.variance = Standardabweichung + +floodmap.wmsbackground = Hintergrundkarte +floodmap.riveraxis = Flussachse +floodmap.uesk = \u00dcberschwemmungsfl\u00e4che +floodmap.barriers = Digitalisierte Objekte +floodmap.kms = Kilometrierung +floodmap.qps = Querprofilspuren +floodmap.hws = Hochwasserschutzanlagen +floodmap.catchment = Einzugsgebiet +floodmap.floodplain = Talaue +floodmap.lines = Linien +floodmap.buildings = Bauwerke +floodmap.fixpoints = Festpunkte +floodmap.floodmaps = \u00dcberschwemmungsfl\u00e4che +floodmap.usershape = Benutzerdaten + +wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange. +wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten. + +wsp.selected.string = {0} + +Mosel = Mosel +Saar = Saar +Elbe = Elbe + +state.map.river = Gew\u00e4sser + +spline.interpolation.failed = Spline interpolation fehlgeschlagen. +cannot.find.w.for.q = W zu Q = {0,number,#.##} kann nicht ermittelt werden. +cannot.find.q = Q = {0,number,#.##} konnte nicht gefunden werden. +no.ws.found = Keine Ws gefunden. +no.q.found.in.column = In Spalte {0,integer} wurde kein Q gefunden. +spline.creation.failed = Spline creation failed. +cannot.find.w.or.q = W oder Q konnten nicht ermittelt werden. +km.not.found = Passender Kilometer konnte nicht gefunden werden. +cannot.create.wq.relation = W/Q-Beziehung konnte nicht ermittelt werden. +cannot.create.index.q.relation = Spaltenindex/Q-Beziehung konnte nicht erstellt werden. + +w.w.qkm1.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. +w.w.wkm1.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. +w.w.qkm2.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. +w.w.wkm2.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. + +cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln. +cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden. +cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln. + +more.than.one.q.for.w = Mehr als ein Q f\u00fcr W = {0,number,#.##} gefunden. + +no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt. +no.gauge.selected = Kein Pegel ausgew\u00e4hlt. +no.locations.selected = Keine Orte angegeben. +no.kms.selected = Keine Kilometerstationen angegeben. +converting.ws.to.qs.failed = Konvertierung von Ws zu Qs fehlgeschlagen. +no.wst.for.river = Keine zum Gew\u00e4sser passende WST gefunden. +no.range.found = Kein passender Pegel gefunden. +no.gauge.found.for.km = Zur gegebenen Kilometerstation existiert kein Pegel. +cannot.create.segments = Flussabschnitte konnten nicht erzeugt werden. +cannot.compute.discharge.curve = Die Abflusskurve konnte nicht berechnet werden.. +cannot.find.ds = Dauerzahlen konnten nicht gefunden werden. +no.segments.found = Keine Flussabschnitte gefunden. +no.values.given = Keine Werte angegeben. +cannot.interpolate.w.q = W/Q-Wert konnte nicht interpoliert werden. + +manualpoints = Manuelle Punkte + +no.reference.start.km = Keine Startkilometerstation angegeben. +no.reference.end.kms = Keine Endkilometerstation(en) angegeben. +waterlevels = Wasserst\u00e4nde + +help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe +help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO +help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten +help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke +help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten +help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen +help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels +help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels +help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke +help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage +help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells +help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile +help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung +help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde +help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario +help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels +help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes +help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart + +fix.reference.period=Bezugszeitraum +fix.reference.period.event=Bezugsereignis +fix.reference.period.event.short=B +fix.analysis.short=A +fix.analysis.periods=Analysezeitr\u00e4ume +fix.derivative=Ableitung +fix.outlier=Ausrei\u00dfer +fix.analysis=Analyseereignis +fix.deviation=Standardabweichung +fix.reference.deviation=Abweichung im Bezugszeitraum +fix.vollmer.wq.curve=W/Q +fix.vollmer.wq.outliers=Ausrei\u00dfer +fix.vollmer.wq.events=Ereignisse +qsectors=Abfluss-Sektoren + +chart.fix.deltawt.title=Abweichungen von der Ausgleichskurve an Kilometer {0} +chart.fix.deltawt.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short} +chart.fix.deltawt.xaxis.label=Datum +chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm] + +chart.fixings.wq.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short} +chart.fixings.wq.subtitle1={0,date,short} bis {1,date,short} + +chart.fix.wq.subtitle=Gew\u00e4sser: {0}; Zeitraum: {1,date,short} bis {2,date,short} + +chart.fixings.longitudinalsection.title=L\u00e4ngsschnitt + +chart.fixings.deltawt.title = Abweichungen von der Ausgleichskurve am Kilometer {0} + +export.fixings.deltawt.csv.header.km=km +export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm] +export.fixings.deltawt.csv.header.q=Abfluss [m\u00b3/s] +export.fixings.deltawt.csv.header.w=Wasserstand [m] +export.fixings.deltawt.csv.header.t=Datum +export.fixings.deltawt.csv.t.format=dd.MM.yyyy +export.fixings.deltawt.csv.header.time.range=Status +export.fixings.deltawt.csv.reference=B +export.fixings.deltawt.csv.analysis=A{0,number,integer} + +fix.missing.river=Kein Gew\u00e4sser gew\u00e4hlt +fix.missing.from=Kein Startkilometer gew\u00e4hlt +fix.missing.to=Kein Endkilometer gew\u00e4hlt +fix.missing.step=Keine Schrittweite angegeben +fix.missing.function=Unbekannter Funktions-Typ +fix.missing.events=Liste der Ereignisse fehlt +fix.missing.reference.period=Kein Bezugszeitraum angegeben +fix.missing.analysis.periods=Keine Analysezeitr\u00e4ume angegeben +fix.missing.qstart.sector=Fehlender unterer Abflusssektor +fix.missing.qend.sector=Fehlender oberer Abflusssektor +fix.missing.prepocessing=Kein Information \u00fcber Aussrei\u00dfertests vorhanden +fix.no.overview.available=Keine Daten\u00fcbersicht vorhanden +fix.invalid.function.name=Unbekannter Funktionsname +fix.too.less.data.colums=Zuwenig Daten f\u00fcr eine Kurvenanpassung +fix.fitting.failed=Kurvenanpassung fehlgeschlagen +fix.invalid.values=Ung\u00fcltige Werte +fix.cannot.load.data=Daten konnten nicht aus der Datenbank geladen werden + +fix.km.chart.q.sector.border0=(MNQ + MQ)/2 +fix.km.chart.q.sector.border1=(MQ + MHQ)/2 +fix.km.chart.q.sector.border2=HQ5 +fix.km.chart.label.date=dd.MM.yyyy +fix.km.chart.title=Fixierungen {0} km {1,number,#.###} +fix.km.chart.q.axis=Q [m\u00b3/s] +fix.km.chart.w.axis=W [NN + m] +fix.km.chart.measured=gemessen +fix.km.chart.interpolated=interpoliert + +fix.export.at.header = Abflusskurve aus der Fixierungsanalyse f\u00fcr {0} {0}-km: {1} +sq.km.chart.label = Messstellen +sq.km.chart.title = Messstellen +sq.km.chart.km.axis = km +sq.km.chart.date.axis = Datum + +module.winfo = WINFO +module.minfo = MINFO +module.fixanalysis = Fixierungsanalyse +module.new_map = Neue Karte +module.new_chart = Neues Diagramm + +load_diameter = Geschiebedurchmesser +bed_diameter = Sohldurchmesser + +area.label.template = Fl\u00e4che = %s m\u00b3 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/resources/messages_en.properties Fri Sep 28 12:14:47 2012 +0200 @@ -0,0 +1,467 @@ +false=Nein +true=Ja + +state.winfo.river = River +state.winfo.calculation_mode = Calculation Mode +state.winfo.location_distance = Location or distance selection +state.winfo.wq = Input for W/Q data +state.winfo.wq_adapted = Input for W/Q data +state.winfo.location = Choose the location +state.winfo.distance = Choose the range +state.winfo.distance_only = Range selection +state.winfo.uesk.wsp = Choose the waterlevel +state.winfo.uesk.dgm = Digital Terrain Model +state.winfo.uesk.profiles = Interpolated Profiles +state.winfo.uesk.floodplain = Lateral Boundary +state.winfo.uesk.differences = Differences between waterlevel and terrain +state.winfo.uesk.scenario = Flood Plain / Scenario +state.winfo.waterlevel_pair_select = Chosen Differences +state.winfo.historicalq.reference_gauge = Selection of Reference Gauge +state.winfo.historicalq.timerange = Selection of Evaluation time +state.winfo.historicalq.mode = Selecion of analyses +state.winfo.reference.curve.input.start = Chosen Reference +state.winfo.reference.curve.input.end = Chosen Evaluation +state.fix.river = River +state.fix.calculation.mode = Calculation Mode +state.fix.location = Distance +state.fix.period = Period +state.fix.gaugerange = Gaugerange +state.fix.eventselect = Event selection +state.fix.analysis.referenceperiod = Reference period +state.fix.analysis.analysisperiods = Analysis period +state.fix.analysis.function = Function +state.fix.analysis.preprocessing = Preprocessing +state.fix.preprocess=preprocess +state.fix.vollmer.function=Function +state.fix.vollmer.preprocessing = Aufbereiten +state.fix.vollmer.qa = Eingabe for W/Q data + +state.minfo.river = River +state.minfo.calculation_mode = Calculation Mode +state.minfo.distance_only = Range selection +state.minfo.dischargestate = Selection of discharge state and channel +state.minfo.sq.location=Location +state.minfo.sq.period=Periods +state.minfo.sq.outliers=Outliers +state.minfo.bed.year_epoch=Year/Epoch +state.minfo.bed.difference_select=Differences +state.minfo.year=Year +state.minfo.epoch=Epoch +state.minfo.bed.location = Location/Distance +state.minfo.bed.periods = Periods +state.minfo.bed.char_diameter = Characteristic Diameter +state.minfo.soundings = Choose Soundings + +year=Year +epoch=Epoch +soundings = Soundings / Epochs + +historical.mode.w = Waterlevel Analyse +historical.mode.q = Discharge Analyse + +calc.surface.curve = Water Level/Surface Curve +calc.flood.map = Flood Plain +calc.discharge.curve = State Discharge Curve/Stage Discharge Relation +calc.duration.curve = Duration Curve +calc.discharge.longitudinal.section = TODO (W bei...) +calc.w.differences = Differences +calc.historical.discharge.curve = Historical Discharge Curve +calc.reference.curve = Reference Curve +calc.fixation.default = Fixation +calc.fixation.vollmer = Balanced Waterlevel +calc.bed.middle = Middle Bed Height +calc.bed.diff = Bed Height Difference +calc.bed.quality = Bed Quality +calc.sediment.load = Sediment Load +calc.flow.velocity = Flow Velocity +calc.sq.relation = Load Discharge Relation +calc.bed.d90 = D90 +calc.bed.d84 = D84 +calc.bed.d80 = D80 +calc.bed.d75 = D75 +calc.bed.d70 = D70 +calc.bed.d60 = D60 +calc.bed.d50 = D50 +calc.bed.d40 = D40 +calc.bed.d30 = D30 +calc.bed.d25 = D25 +calc.bed.d20 = D20 +calc.bed.d16 = D16 +calc.bed.d10 = D10 +calc.bed.dmin = Dmin +calc.bed.dmax = Dmax +calc.bed.dmid = Dmid + +calculation.analysis = Fixinganalysis +calculation.vollmer = relocated Waterlevel Calculation + +state.chart.river = River +state.chart.type = Charttype + +chart.new.durationcurve = Duration Curve +chart.new.computeddischargecurve = Discharge Curve +chart.new.longitudinal_section = Longitudinal Section +chart.new.w_differences = Differences +chart.new.crosssection = Cross Section + +cross_section = Cross Section + +reference_curve = Reference Curve +reference_curve_normalized = Normalized Reference Curve + +scenario.current = Current +scenario.potentiel = Potentiel +scenario.scenario = Scenario + +floodplain.option = Use Floodplain? +floodplain.active = Activ +floodplain.inactive = Inactiv + +river = River +calculation_mode = Calculation Mode +ld_locations = Location(s) +main_channel = Main channel +total_channel = Total channel + +chart.cross_section.title = Cross Section for river {0} +chart.cross_section.subtitle = {0}-km: {1,number,#.###} +chart.cross_section.xaxis.label = Distance [m] +chart.cross_section.yaxis.label = W [NN + m] + +chart.longitudinal.section.title = W-Longitudinal Section +chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.xaxis.label = {0}-km +chart.longitudinal.section.yaxis.label = W [{0}] +chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] +chart.longitudinal.annotations.label = {0}.km +chart.computed.discharge.curve.gauge = Discharge curve at gauge {0} (km {1}) +chart.discharge.curve.title = Discharge Curve +chart.discharge.curve.xaxis.label = Q [m\u00b3/s] +chart.discharge.curve.yaxis.label = W [cm] +chart.discharge.curve.curve.valid.from = {0} (valid from {1,date,short}) +chart.discharge.curve.curve.valid.range = {0} (valid from {1,date,short} - {2,date,short}) +chart.computed.discharge.curve.title = Discharge Curve +chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} +chart.computed.discharge.curve.yaxis.label = W [NN + m] +chart.computed.discharge.curve.curve.label = Discharge Curve {0} km {1} +chart.duration.curve.title = Duration Curve +chart.duration.curve.subtitle = {0}-km: {1,number,#.###} +chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] +chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Waterlevel duration curve for {0} (km: {1}) +chart.duration.curve.curve.q = Discharge duration curve for {0} (km: {1}) +chart.historical.discharge.title = Historical Discharge Curves for Gauge {0} +chart.historical.discharge.subtitle = Gauge {0} +chart.historical.discharge.xaxis.label = Time +chart.historical.discharge.yaxis.label = Q [m\u00b3/s] +chart.historical.discharge.yaxis.second.label = W [cm] + +chart.reference.curve.title = Reference Curve +chart.reference.curve.subtitle = {0} + +chart.fixings.analysis.title = Longitudinal section at km {0} +chart.fixings.wq.subtitle=River: {0}; Range: {1,date,short} to {2,date,short}; Reference period: {3,date,short} to {4,date,short} +chart.fixings.wq.subtitle1={0,date,short} to {1,date,short} + +chart.fixings.derivedcurve.title = Derived curve at km {0} +chart.fixings.deltawt.title = Differences from fitted curve at km {0} +chart.fixings.wq.title = Fixings Analysis at km {0} + +chart.reference.curve.x.axis.in.cm = Reference Gauge(s) [cm] +chart.reference.curve.x.axis.in.m = Reference Station [NN + m] +chart.reference.curve.y.axis.in.cm = Target Gauge(s) [cm] +chart.reference.curve.y.axis.in.m = Target Station(s) [NN + m] + +chart.normalized.reference.curve.title = Reduced Reference Curve + +chart.w_differences.title = Differences +chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.yaxis.label = m +chart.w_differences.yaxis.second.label = W [NN + m] + +chart.bedquality.title=Bed Longitudinal Section +chart.bedquality.xaxis.label=River-Km +chart.bedquality.yaxis.label=Diameter [m] +chart.bedquality.yaxis.label.porosity=Porosity [%] +chart.bedquality.yaxis.label.density=Density [t/m\u00b3] + +chart.sq_relation.xaxis.label = Discharge [m\u00b3/s] +chart.sq_relation.yaxis.label = Transport [kg/s] +chart.sq_relation_a.title = Feinkornanteil +chart.sq_relation_b.title = Sand (Suspensionstransport) +chart.sq_relation_c.title = Sand (Geschiebetransport) +chart.sq_relation_d.title = Fein- und Mittelkies +chart.sq_relation_e.title = Grobkornanteil (> Mittelkies) +chart.sq_relation_f.title = Geschiebetransport gesamt +facet.sq_relation.curve = Potenziell (Geschiebedaten) +facet.sq_relation.measurements = Geschiebedaten +facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0} +facet.sq_relation.outlier.curve = Potenziell Durchgang {0} +facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0} + +facet.longitudinal_section.annotations = POIs +facet.discharge_curves.mainvalues.q = Q (main values) +facet.discharge_curves.mainvalues.w = W (main values) +facet.flow_velocity.mainchannel = v Mainchannel at {0} +facet.flow_velocity.totalchannel = v Totalchannel at {0} +facet.flow_velocity.tauchannel = TAU Mainchannel at {0} +facet.bedheight_middle.single = Bed Height {0,number,####} +facet.bedheight_middle.epoch = Bed Height Epoch {0,number,####} - {1,number,####} +facet.bedquality.bed.porosity.toplayer = Porosity ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.porosity.sublayer = Porosity ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.toplayer = Density ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.density.sublayer = Density ({0,date} - {1,date}) ({2}) +facet.bedquality.bed.diameter.toplayer = {0}_Bed ({1,date} - {2,date}) ({3}) +facet.bedquality.bed.diameter.sublayer = {0}_Bed ({1,date} - {2,date}) ({3}) +facet.bedquality.bedload.diameter = {0}_Bedload +bedquality.toplayer = 0.0m - 0.3m +bedquality.sublayer = 0.1m - 0.5m + +export.waterlevel.csv.header.km = River-Km +export.waterlevel.csv.header.w = W [NN + m] +export.waterlevel.csv.header.q = Q [m\u00b3/s] +export.waterlevel.csv.header.q.desc = Description +export.waterlevel.csv.header.location = Location +export.waterlevel.csv.header.gauge = Reference Gauge +export.waterlevel.csv.meta.result = # Calculation Output - {0} - Waterlevel - FLYS 3 +export.waterlevel.csv.meta.creation = # Time of creation: {0} +export.waterlevel.csv.meta.calculationbase = # Calculation base: {0} +export.waterlevel.csv.meta.river = # River: {0} +export.waterlevel.csv.meta.range = # Location/Range (km): {0} - {1} +export.waterlevel.csv.meta.gauge = # Gauge: {0} +export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} +export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1} +export.waterlevel.csv.not.in.gauge.range = Outside selected gauge +export.computed.discharge.curve.csv.header.w = W [NN + m] +export.computed.discharge.curve.csv.header.q = Q [m\u00b3/s] +export.duration.curve.csv.header.duration = D [Days] +export.duration.curve.csv.header.w = W [NN + m] +export.duration.curve.csv.header.q = Q [m\u00b3/s] +export.discharge.longitudinal.section.csv.header.km = River-Km +export.discharge.longitudinal.section.csv.header.w = W [NN + m] +export.discharge.longitudinal.section.csv.header.cw = W corr. +export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s] +export.discharge.curve.at.header = Computed Discharge Curve for {0} {0}-km: {1} +export.historical.discharge.csv.header.timerange = Timerange +export.historical.discharge.csv.header.waterlevel = Waterlevel +export.historical.discharge.csv.header.discharge = Discharge +export.historical.discharge.csv.header.diff = Difference +export.historical.discharge.csv.header.gaugename = Gaugename +export.reference_curve.csv.header.km = km +export.reference_curve.csv.header.w.cm = W (cm at Gauge) +export.reference_curve.csv.header.w.m = W (m + NHN) +export.reference_curve.csv.header.w.q = equiv. Q (m\u00b3/s) + +export.waterlevel.pdf.mode = Waterlevel +export.computed.discharge.pdf.mode = Computed Dischargecurve +export.duration.pdf.mode = Durationcurve +export.wdifferences.pdf.mode = W Differences +export.historical.discharge.pdf.mode = Historical Discharge +export.reference_curve.pdf.mode = Reference Curve +export.computed.discharge.pdf.file = /jasper/computed-discharge_en.jasper +export.duration.pdf.file = /jasper/duration_en.jasper +export.waterlevel.pdf.file = /jasper/waterlevel_en.jasper +export.wdifferences.pdf.file = /jasper/wdifferences_en.jasper +export.historical.discharge.pdf.file = /jasper/historical-discharge_en.jasper +export.reference_curve.pdf.file = /jasper/reference_en.jasper +export.reference_curve.pdf.file.gauge = /jasper/reference_en_gauge.jasper +export.reference_curve.pdf.file.gauge.end = /jasper/reference_en_gauge_end.jasper +export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_en_gauge_start_end.jasper +export.flow_velocity.csv.header.km = River Km +export.flow_velocity.csv.header.v_total = v Total Channel +export.flow_velocity.csv.header.v_main = v Main Channel +export.flow_velocity.csv.header.tau_main = TAU Main Channel +export.flow_velocity.csv.header.q = Q [m\u00b3/s] +export.flow_velocity.csv.header.locations = Location +export.bedheight_middle.csv.header.km = River km +export.bedheight_middle.csv.header.sounding = Sounding / Epoch +export.bedheight_middle.csv.header.height = middle Bed Height +export.bedheight_middle.csv.header.uncertainty = Uncertainty [m] +export.bedheight_middle.csv.header.datagap = Data Gap +export.bedheight_middle.csv.header.soundingwidth = Sounding Width [m] +export.bedheight_middle.csv.header.width = morphological active width [m] +export.bedheight_middle.csv.header.locations = Location +export.sqrelation.csv.header.parameter = Parameter +export.sqrelation.csv.header.station = Station +export.sqrelation.csv.header.km = River-Km +export.sqrelation.csv.header.function = Function +export.sqrelation.csv.header.gauge = Gauge +export.sqrelation.csv.header.coeff.a = a +export.sqrelation.csv.header.coeff.b = b +export.sqrelation.csv.header.coeff.q = Q +export.sqrelation.csv.header.coeff.r = r^2 +export.sqrelation.csv.header.n.total = n total +export.sqrelation.csv.header.n.outliers = n outliers +export.sqrelation.csv.header.c.duan = C (DUAN) +export.sqrelation.csv.header.c.ferguson = C (FERGUSON) +export.sqrelation.csv.header.variance = Standard variance + +floodmap.wmsbackground = Background Map +floodmap.riveraxis = River Axis +floodmap.uesk = Floodmap +floodmap.barriers = Digitized Objects +floodmap.kms = Kilometrage +floodmap.qps = Crosssection Tracks +floodmap.hws = Flood Control Works +floodmap.catchment = Catchment +floodmap.floodplain = Floodplain +floodmap.lines = Lines +floodmap.buildings = Buildings +floodmap.fixpoints = Fixpoints +floodmap.floodmaps = Floodmaps +floodmap.usershape = User data + +wsplgen.job.queued = WSPLGEN job in queue. +wsplgen.job.error = An unexpected error while starting WSPLGEN occured. + +wsp.selected.string = {0} + +Mosel = Mosel +Saar = Saar +Elbe = Elbe + +state.map.river = River + +spline.interpolation.failed = Spline interpolation failed. +cannot.find.w.for.q = Cannot find W for Q = {0,number,#.##}. +cannot.find.q = Cannot find Q = {0,number,#.##}. +no.ws.found = No Ws found. +no.q.found.in.column = No Q found in {0,integer} column. +spline.creation.failed = Spline creation failed. +cannot.find.w.or.q = Cannot find W or Q. +km.not.found = Cannot find km. +cannot.create.wq.relation = Cannot create W/Q relation. +cannot.create.index.q.relation = Cannot create index/Q relation. + +w.w.qkm1.failed = Calculating Q for WST index {0,number,#.##} failed. +w.w.wkm1.failed = Calculating W for Q = {0,number,#.##} / WST index {1,number,#.##} failed. +w.w.qkm2.failed = Calculating Q for WST index {0,number,#.##} failed. +w.w.wkm2.failed = Calculating W for Q = {0,number,#.##} / WST index {1,number,#.##} failed. + +cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date} +cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange. +cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge. + +more.than.one.q.for.w = Found more Qs for W = {0,number,#.##}. + +no.river.selected = No river selected. +no.gauge.selected = No gauge selected. +no.locations.selected = No locations selected. +no.kms.selected = No KMs selected. +converting.ws.to.qs.failed = Converting Ws to Qs failed. +no.wst.for.river = No WST found for selected river. +no.range.found = No range found. +no.gauge.found.for.km = No gauge found for KM. +cannot.create.segments = Cannot create segments. +cannot.compute.discharge.curve = Cannot create discharge curve. +cannot.find.ds = Cannot find Ds. +no.segments.found = No segments found. +no.values.given = No values given. +cannot.interpolate.w.q = Cannot interpolate W/Q. + +manualpoints = Manual Points + +no.reference.start.km = No reference start station given. +no.reference.end.kms = No reference end station(s) given. +waterlevels = Waterlevels + +help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe +help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO +help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten +help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke +help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten +help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten +help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen +help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels +help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels +help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke +help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage +help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells +help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile +help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung +help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde +help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario +help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels +help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes +help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart + +fix.reference.period=Reference period +fix.reference.period.event=Reference event +fix.reference.period.event.short=R +fix.analysis.short=A +fix.analysis.periods=Analysis periods +fix.derivative=Derivative +fix.outlier=Outlier +fix.analysis=Analysis event +fix.deviation=Standard deviation +fix.reference.deviation=Reference deviation +fix.vollmer.wq.curve=W/Q +fix.vollmer.wq.outliers=Outliers +fix.vollmer.wq.events=Events +qsectors=Discharge Sectors + +chart.fix.deltawt.title=Difference from compensating curve at kilometer {0} +chart.fix.deltawt.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short}; Reference period: {3,date,short} bis {4,date,short} +chart.fix.deltawt.xaxis.label=Date +chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm] + +chart.fix.wq.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short} + +chart.fixings.longitudinalsection.title=Longitudinal section + +export.fixings.deltawt.csv.header.km=km +export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm] +export.fixings.deltawt.csv.header.q=Discharge [m\u00b3/s] +export.fixings.deltawt.csv.header.w=Waterlevel [m] +export.fixings.deltawt.csv.header.t=Date +export.fixings.deltawt.csv.t.format=yyyy/MM/dd +export.fixings.deltawt.csv.header.time.range=State +export.fixings.deltawt.csv.reference=R +export.fixings.deltawt.csv.analysis=A{0,number,integer} + +fix.missing.river=Missing river +fix.missing.from=Missing start km +fix.missing.to=Missing end km +fix.missing.step="Missing step width +fix.missing.function=Missing function type +fix.missing.events=Missing list of events +fix.missing.reference.period=Missing reference period +fix.missing.analysis.periods=Missing analysis periods +fix.missing.qstart.sector=Missing discharge start sector +fix.missing.qend.sector=Missing discharge end sector +fix.missing.prepocessing=Missing info about preprocessing +fix.no.overview.available=No overview available +fix.invalid.function.name=Name of function unknown +fix.too.less.data.colums=Too less data columns for calculation +fix.fitting.failed=Fitting failed +fix.invalid.values=Invalid values +fix.cannot.load.data=Cannot fetch data from database + +fix.km.chart.q.sector.border0=(MNQ + MQ)/2 +fix.km.chart.q.sector.border1=(MQ + MHQ)/2 +fix.km.chart.q.sector.border2=HQ5 +fix.km.chart.label.date=yyyy/MM/dd +fix.km.chart.title=Fixings {0} km {1,number,#.###} +fix.km.chart.q.axis=Q [m\u00b3/s] +fix.km.chart.w.axis=W [NN + m] +fix.km.chart.measured=measured +fix.km.chart.interpolated=interpolated + +fix.export.at.header = Exported fixings discharge curve for {0} {0}-km: {1} +sq.km.chart.label = Measuring Points +sq.km.chart.title = Measuring Points +sq.km.chart.km.axis = km +sq.km.chart.date.axis = Date + +module.winfo = WINFO +module.minfo = MINFO +module.fixanalysis = Fix Analysis +module.new_map = New Map +module.new_chart = New Chart + +load_diameter = Bedload Diameter +bed_diameter = Bed Diameter + +area.label.template = Area = %s m\u00b3